722f8d4efef8f3901057680f2a66b6aabca09f0c
[reactos.git] / modules / rostests / winetests / user32 / msg.c
1 /*
2 * Unit tests for window message handling
3 *
4 * Copyright 1999 Ove Kaaven
5 * Copyright 2003 Dimitrie O. Paun
6 * Copyright 2004,2005,2016 Dmitry Timoshkov
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23 #include "precomp.h"
24
25 #include <dbt.h>
26
27 #define MDI_FIRST_CHILD_ID 2004
28
29 /* undocumented SWP flags - from SDK 3.1 */
30 #define SWP_NOCLIENTSIZE 0x0800
31 #define SWP_NOCLIENTMOVE 0x1000
32 #define SWP_STATECHANGED 0x8000
33
34 #define SW_NORMALNA 0xCC /* undoc. flag in MinMaximize */
35
36 #ifndef WM_KEYF1
37 #define WM_KEYF1 0x004d
38 #endif
39
40 #ifndef WM_SYSTIMER
41 #define WM_SYSTIMER 0x0118
42 #endif
43
44 #define WND_PARENT_ID 1
45 #define WND_POPUP_ID 2
46 #define WND_CHILD_ID 3
47
48 #ifndef WM_LBTRACKPOINT
49 #define WM_LBTRACKPOINT 0x0131
50 #endif
51
52 #ifdef __i386__
53 #define ARCH "x86"
54 #elif defined __x86_64__
55 #define ARCH "amd64"
56 #elif defined __arm__
57 #define ARCH "arm"
58 #elif defined __aarch64__
59 #define ARCH "arm64"
60 #else
61 #define ARCH "none"
62 #endif
63
64 static BOOL (WINAPI *pActivateActCtx)(HANDLE,ULONG_PTR*);
65 static HANDLE (WINAPI *pCreateActCtxW)(PCACTCTXW);
66 static BOOL (WINAPI *pDeactivateActCtx)(DWORD,ULONG_PTR);
67 static BOOL (WINAPI *pGetCurrentActCtx)(HANDLE *);
68 static BOOL (WINAPI *pQueryActCtxW)(DWORD,HANDLE,void*,ULONG,void*,SIZE_T,SIZE_T*);
69 static void (WINAPI *pReleaseActCtx)(HANDLE);
70
71 /* encoded DRAWITEMSTRUCT into an LPARAM */
72 typedef struct
73 {
74 union
75 {
76 struct
77 {
78 UINT type : 4; /* ODT_* flags */
79 UINT ctl_id : 4; /* Control ID */
80 UINT item_id : 4; /* Menu item ID */
81 UINT action : 4; /* ODA_* flags */
82 UINT state : 16; /* ODS_* flags */
83 } item;
84 LPARAM lp;
85 } u;
86 } DRAW_ITEM_STRUCT;
87
88 /* encoded MEASUREITEMSTRUCT into a WPARAM */
89 typedef struct
90 {
91 union
92 {
93 struct
94 {
95 UINT CtlType : 4;
96 UINT CtlID : 4;
97 UINT itemID : 4;
98 UINT wParam : 20;
99 } item;
100 WPARAM wp;
101 } u;
102 } MEASURE_ITEM_STRUCT;
103
104 static BOOL test_DestroyWindow_flag;
105 static HWINEVENTHOOK hEvent_hook;
106 static HHOOK hKBD_hook;
107 static HHOOK hCBT_hook;
108 static DWORD cbt_hook_thread_id;
109
110 static const WCHAR testWindowClassW[] =
111 { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 };
112
113 static LRESULT WINAPI ParentMsgCheckProcA(HWND, UINT, WPARAM, LPARAM);
114
115 /*
116 FIXME: add tests for these
117 Window Edge Styles (Win31/Win95/98 look), in order of precedence:
118 WS_EX_DLGMODALFRAME: double border, WS_CAPTION allowed
119 WS_THICKFRAME: thick border
120 WS_DLGFRAME: double border, WS_CAPTION not allowed (but possibly shown anyway)
121 WS_BORDER (default for overlapped windows): single black border
122 none (default for child (and popup?) windows): no border
123 */
124
125 typedef enum {
126 sent=0x1,
127 posted=0x2,
128 parent=0x4,
129 wparam=0x8,
130 lparam=0x10,
131 defwinproc=0x20,
132 beginpaint=0x40,
133 optional=0x80,
134 hook=0x100,
135 winevent_hook=0x200,
136 kbd_hook=0x400
137 } msg_flags_t;
138
139 struct message {
140 UINT message; /* the WM_* code */
141 msg_flags_t flags; /* message props */
142 WPARAM wParam; /* expected value of wParam */
143 LPARAM lParam; /* expected value of lParam */
144 WPARAM wp_mask; /* mask for wParam checks */
145 LPARAM lp_mask; /* mask for lParam checks */
146 };
147
148 struct recvd_message {
149 UINT message; /* the WM_* code */
150 msg_flags_t flags; /* message props */
151 HWND hwnd; /* window that received the message */
152 WPARAM wParam; /* expected value of wParam */
153 LPARAM lParam; /* expected value of lParam */
154 int line; /* source line where logged */
155 const char *descr; /* description for trace output */
156 char output[512]; /* trace output */
157 };
158
159 /* Empty message sequence */
160 static const struct message WmEmptySeq[] =
161 {
162 { 0 }
163 };
164 /* CreateWindow (for overlapped window, not initially visible) (16/32) */
165 static const struct message WmCreateOverlappedSeq[] = {
166 { HCBT_CREATEWND, hook },
167 { WM_GETMINMAXINFO, sent },
168 { WM_NCCREATE, sent },
169 { WM_NCCALCSIZE, sent|wparam, 0 },
170 { 0x0093, sent|defwinproc|optional },
171 { 0x0094, sent|defwinproc|optional },
172 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
173 { WM_CREATE, sent },
174 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
175 { 0 }
176 };
177 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
178 * for a not visible overlapped window.
179 */
180 static const struct message WmSWP_ShowOverlappedSeq[] = {
181 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
182 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
183 { WM_NCPAINT, sent|wparam|optional, 1 },
184 { WM_GETTEXT, sent|defwinproc|optional },
185 { WM_ERASEBKGND, sent|optional },
186 { HCBT_ACTIVATE, hook },
187 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
188 { WM_NOTIFYFORMAT, sent|optional },
189 { WM_QUERYUISTATE, sent|optional },
190 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
191 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x: SWP_NOSENDCHANGING */
192 { WM_ACTIVATEAPP, sent|wparam, 1 },
193 { WM_NCACTIVATE, sent },
194 { WM_GETTEXT, sent|defwinproc|optional },
195 { WM_ACTIVATE, sent|wparam, 1 },
196 { HCBT_SETFOCUS, hook },
197 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
198 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
199 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
200 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
201 { WM_GETTEXT, sent|optional },
202 { WM_NCPAINT, sent|wparam|optional, 1 },
203 { WM_GETTEXT, sent|defwinproc|optional },
204 { WM_ERASEBKGND, sent|optional },
205 /* Win9x adds SWP_NOZORDER below */
206 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
207 { WM_GETTEXT, sent|optional },
208 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
209 { WM_NCPAINT, sent|wparam|optional, 1 },
210 { WM_ERASEBKGND, sent|optional },
211 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
212 { WM_SYNCPAINT, sent|optional },
213 { WM_GETTITLEBARINFOEX, sent|optional },
214 { WM_PAINT, sent|optional },
215 { WM_NCPAINT, sent|beginpaint|optional },
216 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
217 { WM_ERASEBKGND, sent|beginpaint|optional },
218 { 0 }
219 };
220 /* SetWindowPos(SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE)
221 * for a visible overlapped window.
222 */
223 static const struct message WmSWP_HideOverlappedSeq[] = {
224 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
225 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
226 { HCBT_ACTIVATE, hook|optional },
227 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
228 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
229 { WM_NCACTIVATE, sent|optional },
230 { WM_ACTIVATE, sent|optional },
231 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
232 { 0 }
233 };
234
235 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
236 * for a visible overlapped window.
237 */
238 static const struct message WmSWP_ResizeSeq[] = {
239 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
240 { WM_GETMINMAXINFO, sent|defwinproc },
241 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
242 { WM_NCPAINT, sent|optional },
243 { WM_GETTEXT, sent|defwinproc|optional },
244 { WM_ERASEBKGND, sent|optional },
245 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
246 { WM_SIZE, sent|defwinproc|optional },
247 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
248 { WM_NCPAINT, sent|optional },
249 { WM_GETTEXT, sent|defwinproc|optional },
250 { WM_ERASEBKGND, sent|optional },
251 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
252 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
253 { 0 }
254 };
255
256 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE)
257 * for a visible popup window.
258 */
259 static const struct message WmSWP_ResizePopupSeq[] = {
260 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE },
261 { WM_GETMINMAXINFO, sent|defwinproc|optional }, /* Win9x */
262 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
263 { WM_NCPAINT, sent|optional },
264 { WM_GETTEXT, sent|defwinproc|optional },
265 { WM_ERASEBKGND, sent|optional },
266 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
267 { WM_SIZE, sent|defwinproc|wparam|optional, SIZE_RESTORED },
268 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
269 { WM_NCPAINT, sent|optional },
270 { WM_GETTEXT, sent|defwinproc|optional },
271 { WM_ERASEBKGND, sent|optional },
272 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
273 { 0 }
274 };
275
276 /* SetWindowPos(SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE)
277 * for a visible overlapped window.
278 */
279 static const struct message WmSWP_MoveSeq[] = {
280 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE },
281 { WM_NCPAINT, sent|optional },
282 { WM_GETTEXT, sent|defwinproc|optional },
283 { WM_ERASEBKGND, sent|optional },
284 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
285 { WM_MOVE, sent|defwinproc|wparam, 0 },
286 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
287 { 0 }
288 };
289 /* Resize with SetWindowPos(SWP_NOZORDER)
290 * for a visible overlapped window
291 * SWP_NOZORDER is stripped by the logging code
292 */
293 static const struct message WmSWP_ResizeNoZOrder[] = {
294 { WM_WINDOWPOSCHANGING, sent|wparam, /*SWP_NOZORDER|*/SWP_NOACTIVATE },
295 { WM_GETMINMAXINFO, sent|defwinproc },
296 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
297 { WM_NCPAINT, sent|optional },
298 { WM_GETTEXT, sent|defwinproc|optional },
299 { WM_ERASEBKGND, sent|optional },
300 { WM_WINDOWPOSCHANGED, sent|wparam|optional, /*SWP_NOZORDER|*/SWP_NOACTIVATE, 0,
301 SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE },
302 { WM_MOVE, sent|defwinproc|optional },
303 { WM_SIZE, sent|defwinproc|optional },
304 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
305 { WM_NCPAINT, sent|optional }, /* Win9x doesn't send it */
306 { WM_GETTEXT, sent|defwinproc|optional }, /* Win9x doesn't send it */
307 { WM_ERASEBKGND, sent|optional }, /* Win9x doesn't send it */
308 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
309 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
310 { 0 }
311 };
312
313 /* Switch visible mdi children */
314 static const struct message WmSwitchChild[] = {
315 /* Switch MDI child */
316 { WM_MDIACTIVATE, sent },/* in the MDI client */
317 { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 1st MDI child */
318 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
319 { WM_CHILDACTIVATE, sent },/* in the 1st MDI child */
320 /* Deactivate 2nd MDI child */
321 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
322 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
323 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
324 /* Preparing for maximize and maximize the 1st MDI child */
325 { WM_GETMINMAXINFO, sent|defwinproc }, /* in the 1st MDI child */
326 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED }, /* in the 1st MDI child */
327 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
328 { WM_CHILDACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
329 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 1st MDI child */
330 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED }, /* in the 1st MDI child */
331 /* Lock redraw 2nd MDI child */
332 { WM_SETREDRAW, sent|wparam|defwinproc, 0 }, /* in the 2nd MDI child */
333 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
334 /* Restore 2nd MDI child */
335 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },/* in the 2nd MDI child */
336 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
337 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
338 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED }, /* in the 2nd MDI child */
339 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED }, /* in the 2nd MDI child */
340 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 2nd MDI child */
341 /* Redraw 2nd MDI child */
342 { WM_SETREDRAW, sent|wparam|defwinproc, 1 },/* in the 2nd MDI child */
343 /* Redraw MDI frame */
344 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },/* in MDI frame */
345 { WM_NCCALCSIZE, sent|wparam, 1 },/* in MDI frame */
346 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in MDI frame */
347 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in MDI frame */
348 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
349 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
350 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 1st MDI child */
351 { HCBT_SETFOCUS, hook },
352 { WM_KILLFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
353 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },/* in the 1st MDI child */
354 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
355 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
356 { WM_SETFOCUS, sent },/* in the MDI client */
357 { HCBT_SETFOCUS, hook },
358 { WM_KILLFOCUS, sent },/* in the MDI client */
359 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
360 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 }, /* in the 1st MDI child */
361 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
362 { WM_SETFOCUS, sent|defwinproc }, /* in the 1st MDI child */
363 { WM_MDIACTIVATE, sent|defwinproc },/* in the 1st MDI child */
364 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, /* in the 1st MDI child */
365 { 0 }
366 };
367
368 /* Switch visible not maximized mdi children */
369 static const struct message WmSwitchNotMaximizedChild[] = {
370 /* Switch not maximized MDI child */
371 { WM_MDIACTIVATE, sent },/* in the MDI client */
372 { WM_WINDOWPOSCHANGING, sent|wparam,SWP_NOSIZE|SWP_NOMOVE },/* in the 2nd MDI child */
373 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
374 { WM_CHILDACTIVATE, sent },/* in the 2nd MDI child */
375 /* Deactivate 1st MDI child */
376 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
377 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
378 /* Activate 2nd MDI child */
379 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE}, /* in the 2nd MDI child */
380 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 }, /* in the 2nd MDI child */
381 { HCBT_SETFOCUS, hook }, /* in the 1st MDI child */
382 { WM_KILLFOCUS, sent|defwinproc }, /* in the 1st MDI child */
383 { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
384 { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */
385 { WM_SETFOCUS, sent, 0 }, /* in the MDI client */
386 { HCBT_SETFOCUS, hook },
387 { WM_KILLFOCUS, sent }, /* in the MDI client */
388 { WM_IME_SETCONTEXT, sent|optional }, /* in the MDI client */
389 { WM_IME_SETCONTEXT, sent|defwinproc|optional }, /* in the 1st MDI child */
390 { WM_SETFOCUS, sent|defwinproc }, /* in the 2nd MDI child */
391 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 2nd MDI child */
392 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE}, /* in the 2nd MDI child */
393 { 0 }
394 };
395
396
397 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
398 SWP_NOZORDER|SWP_FRAMECHANGED)
399 * for a visible overlapped window with WS_CLIPCHILDREN style set.
400 */
401 static const struct message WmSWP_FrameChanged_clip[] = {
402 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
403 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
404 { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
405 { WM_GETTEXT, sent|parent|defwinproc|optional },
406 { WM_ERASEBKGND, sent|parent|optional }, /* FIXME: remove optional once Wine is fixed */
407 { WM_NCPAINT, sent }, /* wparam != 1 */
408 { WM_ERASEBKGND, sent },
409 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
410 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
411 { WM_PAINT, sent },
412 { 0 }
413 };
414 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|
415 SWP_NOZORDER|SWP_FRAMECHANGED)
416 * for a visible overlapped window.
417 */
418 static const struct message WmSWP_FrameChangedDeferErase[] = {
419 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
420 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
421 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_DEFERERASE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
422 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
423 { WM_PAINT, sent|parent|optional },
424 { WM_NCPAINT, sent|beginpaint|parent|optional }, /* wparam != 1 */
425 { WM_GETTEXT, sent|beginpaint|parent|defwinproc|optional },
426 { WM_PAINT, sent },
427 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
428 { WM_ERASEBKGND, sent|beginpaint|optional },
429 { 0 }
430 };
431
432 /* SetWindowPos(SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|
433 SWP_NOZORDER|SWP_FRAMECHANGED)
434 * for a visible overlapped window without WS_CLIPCHILDREN style set.
435 */
436 static const struct message WmSWP_FrameChanged_noclip[] = {
437 { WM_WINDOWPOSCHANGING, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED },
438 { WM_NCCALCSIZE, sent|wparam|parent, 1 },
439 { WM_NCPAINT, sent|parent|optional }, /* wparam != 1 */
440 { WM_GETTEXT, sent|parent|defwinproc|optional },
441 { WM_ERASEBKGND, sent|parent|optional },
442 { WM_WINDOWPOSCHANGED, sent|wparam|parent, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
443 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
444 { WM_PAINT, sent },
445 { WM_NCPAINT, sent|beginpaint }, /* wparam != 1 */
446 { WM_ERASEBKGND, sent|beginpaint|optional },
447 { 0 }
448 };
449
450 /* ShowWindow(SW_SHOW) for a not visible overlapped window */
451 static const struct message WmShowOverlappedSeq[] = {
452 { WM_SHOWWINDOW, sent|wparam, 1 },
453 { WM_NCPAINT, sent|wparam|optional, 1 },
454 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
455 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
456 { WM_NCPAINT, sent|wparam|optional, 1 },
457 { WM_GETTEXT, sent|defwinproc|optional },
458 { WM_ERASEBKGND, sent|optional },
459 { HCBT_ACTIVATE, hook|optional },
460 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
461 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
462 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
463 { WM_NCPAINT, sent|wparam|optional, 1 },
464 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
465 { WM_NCACTIVATE, sent|wparam|optional, 1 },
466 { WM_GETTEXT, sent|defwinproc|optional },
467 { WM_ACTIVATE, sent|wparam|optional, 1 },
468 { HCBT_SETFOCUS, hook|optional },
469 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
470 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
471 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
472 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
473 { WM_GETTEXT, sent|optional },
474 { WM_NCPAINT, sent|wparam|optional, 1 },
475 { WM_GETTEXT, sent|defwinproc|optional },
476 { WM_ERASEBKGND, sent|optional },
477 /* Win9x adds SWP_NOZORDER below */
478 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
479 { WM_NCCALCSIZE, sent|optional },
480 { WM_GETTEXT, sent|optional },
481 { WM_NCPAINT, sent|optional },
482 { WM_ERASEBKGND, sent|optional },
483 { WM_SYNCPAINT, sent|optional },
484 #if 0 /* CreateWindow/ShowWindow(SW_SHOW) also generates WM_SIZE/WM_MOVE
485 * messages. Does that mean that CreateWindow doesn't set initial
486 * window dimensions for overlapped windows?
487 */
488 { WM_SIZE, sent },
489 { WM_MOVE, sent },
490 #endif
491 { WM_PAINT, sent|optional },
492 { WM_NCPAINT, sent|beginpaint|optional },
493 { 0 }
494 };
495 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible overlapped window */
496 static const struct message WmShowMaxOverlappedSeq[] = {
497 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
498 { WM_GETMINMAXINFO, sent },
499 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
500 { WM_GETMINMAXINFO, sent|defwinproc },
501 { WM_NCCALCSIZE, sent|wparam, TRUE },
502 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
503 { HCBT_ACTIVATE, hook|optional },
504 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
505 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
506 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
507 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
508 { WM_NCACTIVATE, sent|wparam|optional, 1 },
509 { WM_GETTEXT, sent|defwinproc|optional },
510 { WM_ACTIVATE, sent|wparam|optional, 1 },
511 { HCBT_SETFOCUS, hook|optional },
512 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
513 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
514 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
515 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
516 { WM_GETTEXT, sent|optional },
517 { WM_NCPAINT, sent|wparam|optional, 1 },
518 { WM_GETTEXT, sent|defwinproc|optional },
519 { WM_ERASEBKGND, sent|optional },
520 /* Win9x adds SWP_NOZORDER below */
521 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
522 { WM_MOVE, sent|defwinproc },
523 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
524 { WM_GETTEXT, sent|optional },
525 { WM_NCCALCSIZE, sent|optional },
526 { WM_NCPAINT, sent|optional },
527 { WM_ERASEBKGND, sent|optional },
528 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
529 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
530 { WM_SYNCPAINT, sent|optional },
531 { WM_GETTITLEBARINFOEX, sent|optional },
532 { WM_PAINT, sent|optional },
533 { WM_NCPAINT, sent|beginpaint|optional },
534 { WM_ERASEBKGND, sent|beginpaint|optional },
535 { 0 }
536 };
537 /* ShowWindow(SW_RESTORE) for a not visible maximized overlapped window */
538 static const struct message WmShowRestoreMaxOverlappedSeq[] = {
539 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
540 { WM_GETTEXT, sent|optional },
541 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
542 { WM_GETMINMAXINFO, sent|defwinproc },
543 { WM_NCCALCSIZE, sent|wparam, TRUE },
544 { WM_NCPAINT, sent|optional },
545 { WM_GETTEXT, sent|defwinproc|optional },
546 { WM_ERASEBKGND, sent|optional },
547 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
548 { WM_MOVE, sent|defwinproc|optional },
549 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
550 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
551 { WM_NCPAINT, sent|optional },
552 { WM_ERASEBKGND, sent|optional },
553 { WM_PAINT, sent|optional },
554 { WM_GETTITLEBARINFOEX, sent|optional },
555 { WM_NCPAINT, sent|beginpaint|optional },
556 { WM_ERASEBKGND, sent|beginpaint|optional },
557 { 0 }
558 };
559 /* ShowWindow(SW_RESTORE) for a not visible minimized overlapped window */
560 static const struct message WmShowRestoreMinOverlappedSeq[] = {
561 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
562 { WM_QUERYOPEN, sent|optional },
563 { WM_GETTEXT, sent|optional },
564 { WM_NCACTIVATE, sent|wparam|optional, 1 },
565 { WM_WINDOWPOSCHANGING, sent|optional }, /* SWP_NOSIZE|SWP_NOMOVE */
566 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
567 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
568 { WM_MOVE, sent|optional },
569 { WM_SIZE, sent|wparam|optional, SIZE_RESTORED },
570 { WM_GETTEXT, sent|optional },
571 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED|SWP_NOCOPYBITS },
572 { WM_GETMINMAXINFO, sent|defwinproc|optional },
573 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
574 { HCBT_ACTIVATE, hook|optional },
575 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
576 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
577 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
578 { WM_NCACTIVATE, sent|wparam|optional, 1 },
579 { WM_GETTEXT, sent|defwinproc|optional },
580 { WM_ACTIVATE, sent|wparam|optional, 1 },
581 { HCBT_SETFOCUS, hook|optional },
582 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
583 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
584 { WM_SETFOCUS, sent|wparam|defwinproc|optional, 0 },
585 { WM_GETTEXT, sent|optional },
586 { WM_NCPAINT, sent|wparam|optional, 1 },
587 { WM_GETTEXT, sent|defwinproc|optional },
588 { WM_ERASEBKGND, sent },
589 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_STATECHANGED|SWP_FRAMECHANGED|SWP_NOCOPYBITS },
590 { WM_MOVE, sent|defwinproc },
591 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
592 { HCBT_SETFOCUS, hook|optional },
593 { WM_SETFOCUS, sent|wparam|optional, 0 },
594 { WM_NCCALCSIZE, sent|wparam|optional, TRUE },
595 { WM_NCPAINT, sent|wparam|optional, 1 },
596 { WM_ERASEBKGND, sent|optional },
597 { HCBT_SETFOCUS, hook|optional },
598 { WM_SETFOCUS, sent|wparam|optional, 0 },
599 { WM_ACTIVATE, sent|wparam, 1 },
600 { WM_GETTEXT, sent|optional },
601 { WM_PAINT, sent|optional },
602 { WM_GETTITLEBARINFOEX, sent|optional },
603 { WM_NCPAINT, sent|beginpaint|optional },
604 { WM_ERASEBKGND, sent|beginpaint|optional },
605 { 0 }
606 };
607 /* ShowWindow(SW_SHOWMINIMIZED) for a not visible overlapped window */
608 static const struct message WmShowMinOverlappedSeq[] = {
609 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
610 { HCBT_SETFOCUS, hook|optional },
611 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
612 { WM_KILLFOCUS, sent|optional },
613 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
614 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
615 { WM_GETTEXT, sent|optional },
616 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCOPYBITS|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
617 { WM_GETMINMAXINFO, sent|defwinproc },
618 { WM_NCCALCSIZE, sent|wparam, TRUE },
619 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
620 { WM_NCPAINT, sent|optional },
621 { WM_GETTEXT, sent|defwinproc|optional },
622 { WM_WINDOWPOSCHANGED, sent },
623 { WM_MOVE, sent|defwinproc },
624 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
625 { WM_NCCALCSIZE, sent|optional },
626 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
627 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
628 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
629 { WM_NCACTIVATE, sent|wparam|optional, 0 },
630 { WM_GETTEXT, sent|defwinproc|optional },
631 { WM_ACTIVATE, sent|optional },
632 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
633
634 /* Vista sometimes restores the window right away... */
635 { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
636 { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
637 { HCBT_MINMAX, hook|optional|lparam, 0, SW_RESTORE },
638 { WM_QUERYOPEN, sent|optional },
639 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
640 { WM_GETMINMAXINFO, sent|optional|defwinproc },
641 { WM_NCCALCSIZE, sent|optional|wparam, TRUE },
642 { HCBT_ACTIVATE, hook|optional },
643 { WM_ACTIVATEAPP, sent|optional|wparam, 1 },
644 { WM_NCACTIVATE, sent|optional },
645 { WM_GETTEXT, sent|optional },
646 { WM_ACTIVATE, sent|optional|wparam, 1 },
647 { HCBT_SETFOCUS, hook|optional },
648 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
649 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
650 { WM_SETFOCUS, sent|optional },
651 { WM_NCPAINT, sent|optional },
652 { WM_GETTEXT, sent|defwinproc|optional },
653 { WM_ERASEBKGND, sent|optional },
654 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
655 { WM_MOVE, sent|defwinproc|optional },
656 { WM_SIZE, sent|defwinproc|optional|wparam, SIZE_RESTORED },
657 { WM_ACTIVATE, sent|optional|wparam, 1 },
658 { WM_SYSCOMMAND, sent|optional|wparam, SC_RESTORE },
659 { HCBT_SYSCOMMAND, hook|optional|wparam, SC_RESTORE },
660
661 { WM_PAINT, sent|optional },
662 { WM_NCPAINT, sent|beginpaint|optional },
663 { WM_ERASEBKGND, sent|beginpaint|optional },
664 { 0 }
665 };
666 /* ShowWindow(SW_HIDE) for a visible overlapped window */
667 static const struct message WmHideOverlappedSeq[] = {
668 { WM_SHOWWINDOW, sent|wparam, 0 },
669 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
670 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
671 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
672 { WM_SIZE, sent|optional }, /* XP doesn't send it */
673 { WM_MOVE, sent|optional }, /* XP doesn't send it */
674 { WM_NCACTIVATE, sent|wparam|optional, 0 },
675 { WM_ACTIVATE, sent|wparam|optional, 0 },
676 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
677 { HCBT_SETFOCUS, hook|optional },
678 { WM_KILLFOCUS, sent|wparam|optional, 0 },
679 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
680 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
681 { 0 }
682 };
683 /* DestroyWindow for a visible overlapped window */
684 static const struct message WmDestroyOverlappedSeq[] = {
685 { HCBT_DESTROYWND, hook },
686 { 0x0090, sent|optional },
687 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
688 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
689 { 0x0090, sent|optional },
690 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
691 { WM_NCACTIVATE, sent|optional|wparam, 0 },
692 { WM_ACTIVATE, sent|optional },
693 { WM_ACTIVATEAPP, sent|optional|wparam, 0 },
694 { WM_KILLFOCUS, sent|optional|wparam, 0 },
695 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
696 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
697 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
698 { WM_DESTROY, sent },
699 { WM_NCDESTROY, sent },
700 { 0 }
701 };
702 /* CreateWindow(WS_MAXIMIZE|WS_VISIBLE) for popup window */
703 static const struct message WmCreateMaxPopupSeq[] = {
704 { HCBT_CREATEWND, hook },
705 { WM_NCCREATE, sent },
706 { WM_NCCALCSIZE, sent|wparam, 0 },
707 { WM_CREATE, sent },
708 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
709 { WM_SIZE, sent|wparam, SIZE_RESTORED },
710 { WM_MOVE, sent },
711 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
712 { WM_GETMINMAXINFO, sent },
713 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
714 { WM_NCCALCSIZE, sent|wparam, TRUE },
715 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
716 { WM_MOVE, sent|defwinproc },
717 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
718 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
719 { WM_SHOWWINDOW, sent|wparam, 1 },
720 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
721 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
722 { HCBT_ACTIVATE, hook },
723 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
724 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
725 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
726 { WM_NCPAINT, sent|wparam|optional, 1 },
727 { WM_ERASEBKGND, sent|optional },
728 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_NOMOVE|SWP_NOSIZE },
729 { WM_ACTIVATEAPP, sent|wparam, 1 },
730 { WM_NCACTIVATE, sent },
731 { WM_ACTIVATE, sent|wparam, 1 },
732 { HCBT_SETFOCUS, hook },
733 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
734 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
735 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
736 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
737 { WM_GETTEXT, sent|optional },
738 { WM_SYNCPAINT, sent|wparam|optional, 4 },
739 { WM_NCPAINT, sent|wparam|optional, 1 },
740 { WM_ERASEBKGND, sent|optional },
741 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
742 { WM_ERASEBKGND, sent|defwinproc|optional },
743 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
744 { 0 }
745 };
746 /* CreateWindow(WS_MAXIMIZE) for popup window, not initially visible */
747 static const struct message WmCreateInvisibleMaxPopupSeq[] = {
748 { HCBT_CREATEWND, hook },
749 { WM_NCCREATE, sent },
750 { WM_NCCALCSIZE, sent|wparam, 0 },
751 { WM_CREATE, sent },
752 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
753 { WM_SIZE, sent|wparam, SIZE_RESTORED },
754 { WM_MOVE, sent },
755 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
756 { WM_GETMINMAXINFO, sent },
757 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED },
758 { WM_NCCALCSIZE, sent|wparam, TRUE },
759 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
760 { WM_MOVE, sent|defwinproc },
761 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
762 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
763 { 0 }
764 };
765 /* ShowWindow(SW_SHOWMAXIMIZED) for a resized not visible popup window */
766 static const struct message WmShowMaxPopupResizedSeq_todo[] = {
767 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
768 { WM_GETMINMAXINFO, sent },
769 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
770 { WM_NCCALCSIZE, sent|wparam, TRUE },
771 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
772 { HCBT_ACTIVATE, hook },
773 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
774 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
775 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
776 { WM_NCPAINT, sent|wparam|optional, 1 },
777 { WM_ERASEBKGND, sent|optional },
778 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
779 { WM_ACTIVATEAPP, sent|wparam, 1 },
780 { WM_NCACTIVATE, sent },
781 { WM_ACTIVATE, sent|wparam, 1 },
782 { HCBT_SETFOCUS, hook },
783 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
784 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
785 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
786 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
787 { WM_GETTEXT, sent|optional },
788 { WM_NCPAINT, sent|wparam|optional, 1 },
789 { WM_ERASEBKGND, sent|optional },
790 { WM_WINDOWPOSCHANGED, sent },
791 /* WinNT4.0 sends WM_MOVE */
792 { WM_MOVE, sent|defwinproc|optional },
793 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
794 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
795 { 0 }
796 };
797 static const struct message WmShowMaxPopupResizedSeq[] = {
798 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
799 { WM_GETMINMAXINFO, sent },
800 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
801 { WM_NCCALCSIZE, sent|wparam, TRUE },
802 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
803 { HCBT_ACTIVATE, hook },
804 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
805 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
806 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
807 { WM_NCPAINT, sent|wparam|optional, 1 },
808 { WM_ERASEBKGND, sent|optional },
809 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
810 { WM_ACTIVATEAPP, sent|wparam, 1 },
811 { WM_NCACTIVATE, sent },
812 { WM_ACTIVATE, sent|wparam, 1 },
813 { HCBT_SETFOCUS, hook },
814 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
815 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
816 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
817 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
818 { WM_GETTEXT, sent|optional },
819 { WM_NCPAINT, sent|optional }, /* We'll check WM_NCPAINT behaviour in another test */
820 { WM_ERASEBKGND, sent|optional },
821 { WM_WINDOWPOSCHANGED, sent },
822 /* WinNT4.0 sends WM_MOVE */
823 { WM_MOVE, sent|defwinproc|optional },
824 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
825 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
826 { 0 }
827 };
828 /* ShowWindow(SW_SHOWMAXIMIZED) for a not visible popup window */
829 static const struct message WmShowMaxPopupSeq[] = {
830 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
831 { WM_GETMINMAXINFO, sent },
832 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
833 { WM_NCCALCSIZE, sent|wparam, TRUE },
834 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
835 { HCBT_ACTIVATE, hook },
836 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
837 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
838 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
839 { WM_NCPAINT, sent|wparam|optional, 1 },
840 { WM_ERASEBKGND, sent|optional },
841 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOMOVE|SWP_NOSIZE },
842 { WM_ACTIVATEAPP, sent|wparam, 1 },
843 { WM_NCACTIVATE, sent },
844 { WM_ACTIVATE, sent|wparam, 1 },
845 { HCBT_SETFOCUS, hook },
846 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
847 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
848 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
849 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
850 { WM_GETTEXT, sent|optional },
851 { WM_SYNCPAINT, sent|wparam|optional, 4 },
852 { WM_NCPAINT, sent|wparam|optional, 1 },
853 { WM_ERASEBKGND, sent|optional },
854 { WM_NCPAINT, sent|wparam|defwinproc|optional, 1 },
855 { WM_ERASEBKGND, sent|defwinproc|optional },
856 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE },
857 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
858 { 0 }
859 };
860 /* CreateWindow(WS_VISIBLE) for popup window */
861 static const struct message WmCreatePopupSeq[] = {
862 { HCBT_CREATEWND, hook },
863 { WM_NCCREATE, sent },
864 { WM_NCCALCSIZE, sent|wparam, 0 },
865 { WM_CREATE, sent },
866 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
867 { WM_SIZE, sent|wparam, SIZE_RESTORED },
868 { WM_MOVE, sent },
869 { WM_SHOWWINDOW, sent|wparam, 1 },
870 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
871 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
872 { HCBT_ACTIVATE, hook },
873 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
874 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
875 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
876 { WM_NCPAINT, sent|wparam|optional, 1 },
877 { WM_ERASEBKGND, sent|optional },
878 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
879 { WM_ACTIVATEAPP, sent|wparam, 1 },
880 { WM_NCACTIVATE, sent },
881 { WM_ACTIVATE, sent|wparam, 1 },
882 { HCBT_SETFOCUS, hook },
883 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
884 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
885 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
886 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
887 { WM_GETTEXT, sent|optional },
888 { WM_SYNCPAINT, sent|wparam|optional, 4 },
889 { WM_NCPAINT, sent|wparam|optional, 1 },
890 { WM_ERASEBKGND, sent|optional },
891 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTMOVE|SWP_NOCLIENTSIZE|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE },
892 { 0 }
893 };
894 /* ShowWindow(SW_SHOWMAXIMIZED) for a visible popup window */
895 static const struct message WmShowVisMaxPopupSeq[] = {
896 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
897 { WM_GETMINMAXINFO, sent },
898 { WM_GETTEXT, sent|optional },
899 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
900 { WM_GETTEXT, sent|optional },
901 { WM_NCCALCSIZE, sent|wparam, TRUE },
902 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
903 { WM_NCPAINT, sent|wparam|optional, 1 },
904 { WM_ERASEBKGND, sent|optional },
905 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
906 { WM_MOVE, sent|defwinproc },
907 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
908 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
909 { 0 }
910 };
911 /* CreateWindow (for a child popup window, not initially visible) */
912 static const struct message WmCreateChildPopupSeq[] = {
913 { HCBT_CREATEWND, hook },
914 { WM_NCCREATE, sent },
915 { WM_NCCALCSIZE, sent|wparam, 0 },
916 { WM_CREATE, sent },
917 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
918 { WM_SIZE, sent|wparam, SIZE_RESTORED },
919 { WM_MOVE, sent },
920 { 0 }
921 };
922 /* CreateWindow (for a popup window, not initially visible,
923 * which sets WS_VISIBLE in WM_CREATE handler)
924 */
925 static const struct message WmCreateInvisiblePopupSeq[] = {
926 { HCBT_CREATEWND, hook },
927 { WM_NCCREATE, sent },
928 { WM_NCCALCSIZE, sent|wparam, 0 },
929 { WM_CREATE, sent },
930 { WM_STYLECHANGING, sent },
931 { WM_STYLECHANGED, sent },
932 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
933 { WM_SIZE, sent|wparam, SIZE_RESTORED },
934 { WM_MOVE, sent },
935 { 0 }
936 };
937 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER)
938 * for a popup window with WS_VISIBLE style set
939 */
940 static const struct message WmShowVisiblePopupSeq_2[] = {
941 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
942 { 0 }
943 };
944 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
945 * for a popup window with WS_VISIBLE style set
946 */
947 static const struct message WmShowVisiblePopupSeq_3[] = {
948 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
949 { HCBT_ACTIVATE, hook },
950 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
951 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
952 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
953 { WM_NCACTIVATE, sent },
954 { WM_ACTIVATE, sent|wparam, 1 },
955 { HCBT_SETFOCUS, hook },
956 { WM_KILLFOCUS, sent|parent },
957 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
958 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
959 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
960 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
961 { WM_SETFOCUS, sent|defwinproc },
962 { WM_GETTEXT, sent|optional },
963 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_SHOWWINDOW },
964 { 0 }
965 };
966 /* CreateWindow (for a popup window with WS_VISIBLE style set and extreme location)
967 */
968 static const struct message WmShowPopupExtremeLocationSeq[] = {
969 { HCBT_CREATEWND, hook },
970 { WM_NCCREATE, sent },
971 { WM_NCCALCSIZE, sent|wparam, 0 },
972 { WM_CREATE, sent },
973 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
974 { WM_SIZE, sent|wparam, SIZE_RESTORED },
975 { WM_MOVE, sent },
976 { WM_SHOWWINDOW, sent|wparam, 1 },
977 { WM_WINDOWPOSCHANGING, sent },
978 { HCBT_ACTIVATE, hook },
979 { WM_WINDOWPOSCHANGING, sent|optional },
980 { WM_QUERYNEWPALETTE, sent|optional },
981 { WM_ACTIVATEAPP, sent },
982 { WM_NCACTIVATE, sent },
983 { WM_ACTIVATE, sent },
984 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
985 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
986 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
987 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
988 { HCBT_SETFOCUS, hook },
989 { WM_SETFOCUS, sent|defwinproc },
990 { WM_NCPAINT, sent|wparam, 1 },
991 { WM_ERASEBKGND, sent },
992 { WM_WINDOWPOSCHANGED, sent },
993 /* occasionally received on test machines */
994 { WM_NCPAINT, sent|optional },
995 { WM_ERASEBKGND, sent|optional },
996 { 0 }
997 };
998 /* CreateWindow (for a popup window with WS_VISIBLE style set)
999 */
1000 static const struct message WmShowPopupFirstDrawSeq_1[] = {
1001 { HCBT_CREATEWND, hook },
1002 { WM_NCCREATE, sent },
1003 { WM_NCCALCSIZE, sent|wparam, 0 },
1004 { WM_CREATE, sent },
1005 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1006 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1007 { WM_MOVE, sent },
1008 { WM_SHOWWINDOW, sent|wparam, 1 },
1009 { WM_WINDOWPOSCHANGING, sent },
1010 { HCBT_ACTIVATE, hook },
1011 { WM_WINDOWPOSCHANGING, sent|optional },
1012 { WM_QUERYNEWPALETTE, sent|optional },
1013 { WM_ACTIVATEAPP, sent },
1014 { WM_NCACTIVATE, sent },
1015 { WM_ACTIVATE, sent },
1016 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1017 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1018 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1019 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1020 { HCBT_SETFOCUS, hook },
1021 { WM_SETFOCUS, sent|defwinproc },
1022 { WM_NCPAINT, sent|wparam, 1 },
1023 { WM_ERASEBKGND, sent },
1024 { WM_WINDOWPOSCHANGED, sent },
1025 { WM_PAINT, sent },
1026 /* occasionally received on test machines */
1027 { WM_NCPAINT, sent|beginpaint|optional },
1028 { WM_ERASEBKGND, sent|beginpaint|optional },
1029 { 0 }
1030 };
1031 /* CreateWindow (for a popup window that is shown with ShowWindow(SW_SHOWMAXIMIZED))
1032 */
1033 static const struct message WmShowPopupFirstDrawSeq_2[] = {
1034 { HCBT_CREATEWND, hook },
1035 { WM_NCCREATE, sent },
1036 { WM_NCCALCSIZE, sent|wparam, 0 },
1037 { WM_CREATE, sent },
1038 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1039 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1040 { WM_MOVE, sent },
1041 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1042 { WM_GETMINMAXINFO, sent },
1043 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_STATECHANGED|SWP_SHOWWINDOW|SWP_FRAMECHANGED },
1044 { WM_NCCALCSIZE, sent|wparam, TRUE },
1045 { HCBT_ACTIVATE, hook },
1046 { WM_WINDOWPOSCHANGING, sent|optional },
1047 { WM_NCPAINT, sent|optional|wparam, 1 },
1048 { WM_ERASEBKGND, sent|optional },
1049 { WM_WINDOWPOSCHANGED, sent|optional },
1050 { WM_QUERYNEWPALETTE, sent|optional },
1051 { WM_ACTIVATEAPP, sent },
1052 { WM_NCACTIVATE, sent },
1053 { WM_ACTIVATE, sent },
1054 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1055 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1056 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1057 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1058 { HCBT_SETFOCUS, hook },
1059 { WM_SETFOCUS, sent|defwinproc },
1060 { WM_NCPAINT, sent|wparam, 1 },
1061 { WM_ERASEBKGND, sent },
1062 { WM_WINDOWPOSCHANGED, sent|optional },
1063 { WM_MOVE, sent|defwinproc },
1064 { WM_SIZE, sent|defwinproc, 0 },
1065 { WM_PAINT, sent},
1066 /* occasionally received on test machines */
1067 { WM_NCPAINT, sent|beginpaint|optional },
1068 { WM_ERASEBKGND, sent|beginpaint|optional },
1069 { 0 }
1070 };
1071 static const struct message WmFirstDrawSetWindowPosSeq1[] = {
1072 { HCBT_CREATEWND, hook },
1073 { WM_NCCREATE, sent },
1074 { WM_NCCALCSIZE, sent|wparam, 0 },
1075 { WM_CREATE, sent },
1076 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1077 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1078 { WM_MOVE, sent },
1079 { WM_WINDOWPOSCHANGING, sent },
1080 { HCBT_ACTIVATE, hook },
1081 { WM_WINDOWPOSCHANGING, sent|optional },
1082 { WM_QUERYNEWPALETTE, sent|optional },
1083 { WM_ACTIVATEAPP, sent },
1084 { WM_NCACTIVATE, sent },
1085 { WM_ACTIVATE, sent },
1086 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1087 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1088 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1089 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1090 { HCBT_SETFOCUS, hook },
1091 { WM_SETFOCUS, sent|defwinproc },
1092 { WM_NCPAINT, sent|wparam, 1 },
1093 { WM_ERASEBKGND, sent },
1094 { WM_WINDOWPOSCHANGED, sent },
1095 { WM_MOVE, sent|defwinproc },
1096 { 0 }
1097 };
1098 static const struct message WmFirstDrawSetWindowPosSeq2[] = {
1099 { HCBT_CREATEWND, hook },
1100 { WM_NCCREATE, sent },
1101 { WM_NCCALCSIZE, sent|wparam, 0 },
1102 { WM_CREATE, sent },
1103 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1104 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1105 { WM_MOVE, sent },
1106 { WM_WINDOWPOSCHANGING, sent },
1107 { HCBT_ACTIVATE, hook },
1108 { WM_QUERYNEWPALETTE, sent|optional },
1109 { WM_WINDOWPOSCHANGING, sent|optional },
1110 { WM_ACTIVATEAPP, sent },
1111 { WM_NCACTIVATE, sent },
1112 { WM_ACTIVATE, sent },
1113 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1114 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1115 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1116 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1117 { HCBT_SETFOCUS, hook },
1118 { WM_SETFOCUS, sent|defwinproc },
1119 { WM_WINDOWPOSCHANGED, sent },
1120 { WM_MOVE, sent|defwinproc },
1121 { 0 }
1122 };
1123 static const struct message WmFirstDrawSetWindowPosSeq3[] = {
1124 { HCBT_CREATEWND, hook },
1125 { WM_NCCREATE, sent },
1126 { WM_NCCALCSIZE, sent|wparam, 0 },
1127 { WM_CREATE, sent },
1128 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1129 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1130 { WM_MOVE, sent },
1131 { HCBT_ACTIVATE, hook|optional },
1132 /* Probably shouldn't happen, but not part of this test */
1133 { WM_QUERYNEWPALETTE, sent|optional },
1134 { WM_ACTIVATEAPP, sent|optional },
1135 { WM_NCACTIVATE, sent|optional },
1136 { WM_ACTIVATE, sent|optional },
1137 { HCBT_SETFOCUS, hook|optional },
1138 { WM_SETFOCUS, sent|defwinproc|optional },
1139 { 0 }
1140 };
1141 static const struct message WmFirstDrawSetWindowPosSeq4[] = {
1142 { HCBT_CREATEWND, hook },
1143 { WM_NCCREATE, sent },
1144 { WM_NCCALCSIZE, sent|wparam, 0 },
1145 { WM_CREATE, sent },
1146 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1147 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1148 { WM_MOVE, sent },
1149 { WM_WINDOWPOSCHANGING, sent },
1150 { HCBT_ACTIVATE, hook },
1151 { WM_WINDOWPOSCHANGING, sent|optional },
1152 { WM_QUERYNEWPALETTE, sent|optional },
1153 { WM_ACTIVATEAPP, sent },
1154 { WM_NCACTIVATE, sent },
1155 { WM_ACTIVATE, sent },
1156 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1157 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1158 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1159 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1160 { HCBT_SETFOCUS, hook },
1161 { WM_SETFOCUS, sent|defwinproc },
1162 { WM_NCPAINT, sent|wparam, 1 },
1163 { WM_ERASEBKGND, sent },
1164 { WM_WINDOWPOSCHANGED, sent },
1165 { 0 }
1166 };
1167 static const struct message WmFirstDrawSetWindowPosSeq5[] = {
1168 { HCBT_CREATEWND, hook },
1169 { WM_NCCREATE, sent },
1170 { WM_NCCALCSIZE, sent|wparam, 0 },
1171 { WM_CREATE, sent },
1172 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1173 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1174 { WM_MOVE, sent },
1175 { WM_WINDOWPOSCHANGING, sent },
1176 { HCBT_ACTIVATE, hook },
1177 { WM_WINDOWPOSCHANGING, sent|optional },
1178 { WM_QUERYNEWPALETTE, sent|optional },
1179 { WM_ACTIVATEAPP, sent },
1180 { WM_NCACTIVATE, sent },
1181 { WM_ACTIVATE, sent },
1182 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1183 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
1184 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1185 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1186 { HCBT_SETFOCUS, hook },
1187 { WM_SETFOCUS, sent|defwinproc },
1188 { WM_WINDOWPOSCHANGED, sent },
1189 { 0 }
1190 };
1191 static const struct message WmFirstDrawChildSeq1[] = {
1192 { 0 }
1193 };
1194 static const struct message WmFirstDrawChildSeq2[] = {
1195 { WM_NCPAINT, sent|wparam, 1 },
1196 { WM_ERASEBKGND, sent },
1197 /* occasionally received on test machines */
1198 { WM_NCPAINT, sent|optional },
1199 { WM_ERASEBKGND, sent|optional },
1200 { 0 }
1201 };
1202 /* CreateWindow (for child window, not initially visible) */
1203 static const struct message WmCreateChildSeq[] = {
1204 { HCBT_CREATEWND, hook },
1205 { WM_NCCREATE, sent },
1206 /* child is inserted into parent's child list after WM_NCCREATE returns */
1207 { WM_NCCALCSIZE, sent|wparam, 0 },
1208 { WM_CREATE, sent },
1209 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1210 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1211 { WM_MOVE, sent },
1212 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1213 { 0 }
1214 };
1215 /* CreateWindow (for maximized child window, not initially visible) */
1216 static const struct message WmCreateMaximizedChildSeq[] = {
1217 { HCBT_CREATEWND, hook },
1218 { WM_NCCREATE, sent },
1219 { WM_NCCALCSIZE, sent|wparam, 0 },
1220 { WM_CREATE, sent },
1221 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1222 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1223 { WM_MOVE, sent },
1224 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1225 { WM_GETMINMAXINFO, sent },
1226 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
1227 { WM_NCCALCSIZE, sent|wparam, 1 },
1228 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1229 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1230 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1231 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1232 { 0 }
1233 };
1234 /* CreateWindow (for a child window, initially visible) */
1235 static const struct message WmCreateVisibleChildSeq[] = {
1236 { HCBT_CREATEWND, hook },
1237 { WM_NCCREATE, sent },
1238 /* child is inserted into parent's child list after WM_NCCREATE returns */
1239 { WM_NCCALCSIZE, sent|wparam, 0 },
1240 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1241 { WM_CREATE, sent },
1242 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1243 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1244 { WM_MOVE, sent },
1245 { WM_PARENTNOTIFY, sent|parent|wparam, WM_CREATE },
1246 { WM_SHOWWINDOW, sent|wparam, 1 },
1247 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1248 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1249 { WM_ERASEBKGND, sent|parent|optional },
1250 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1251 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* WinXP */
1252 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1253 { 0 }
1254 };
1255 /* ShowWindow(SW_SHOW) for a not visible child window */
1256 static const struct message WmShowChildSeq[] = {
1257 { WM_SHOWWINDOW, sent|wparam, 1 },
1258 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1259 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1260 { WM_ERASEBKGND, sent|parent|optional },
1261 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1262 { 0 }
1263 };
1264 /* ShowWindow(SW_HIDE) for a visible child window */
1265 static const struct message WmHideChildSeq[] = {
1266 { WM_SHOWWINDOW, sent|wparam, 0 },
1267 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1268 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1269 { WM_ERASEBKGND, sent|parent|optional },
1270 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1271 { 0 }
1272 };
1273 /* ShowWindow(SW_HIDE) for a visible child window checking all parent events*/
1274 static const struct message WmHideChildSeq2[] = {
1275 { WM_SHOWWINDOW, sent|wparam, 0 },
1276 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1277 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1278 { WM_ERASEBKGND, sent|parent|optional },
1279 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1280 { 0 }
1281 };
1282 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1283 * for a not visible child window
1284 */
1285 static const struct message WmShowChildSeq_2[] = {
1286 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1287 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1288 { WM_CHILDACTIVATE, sent },
1289 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1290 { 0 }
1291 };
1292 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE)
1293 * for a not visible child window
1294 */
1295 static const struct message WmShowChildSeq_3[] = {
1296 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1297 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1298 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1299 { 0 }
1300 };
1301 /* SetWindowPos(SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE)
1302 * for a visible child window with a caption
1303 */
1304 static const struct message WmShowChildSeq_4[] = {
1305 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1306 { WM_CHILDACTIVATE, sent },
1307 { 0 }
1308 };
1309 /* ShowWindow(SW_MINIMIZE) for child with invisible parent */
1310 static const struct message WmShowChildInvisibleParentSeq_1[] = {
1311 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1312 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1313 { WM_NCCALCSIZE, sent|wparam, 1 },
1314 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1315 { WM_CHILDACTIVATE, sent|optional },
1316 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
1317 { WM_MOVE, sent|defwinproc },
1318 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1319 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1320 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1321 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1322 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1323 { WM_GETTEXT, sent|optional },
1324 { 0 }
1325 };
1326 /* repeated ShowWindow(SW_MINIMIZE) for child with invisible parent */
1327 static const struct message WmShowChildInvisibleParentSeq_1r[] = {
1328 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
1329 { 0 }
1330 };
1331 /* ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1332 static const struct message WmShowChildInvisibleParentSeq_2[] = {
1333 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1334 { WM_GETMINMAXINFO, sent },
1335 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
1336 { WM_NCCALCSIZE, sent|wparam, 1 },
1337 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1338 { WM_CHILDACTIVATE, sent },
1339 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
1340 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
1341 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1342 { 0 }
1343 };
1344 /* repeated ShowWindow(SW_MAXIMIZE) for child with invisible parent */
1345 static const struct message WmShowChildInvisibleParentSeq_2r[] = {
1346 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
1347 { 0 }
1348 };
1349 /* ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1350 static const struct message WmShowChildInvisibleParentSeq_3[] = {
1351 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1352 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
1353 { WM_NCCALCSIZE, sent|wparam, 1 },
1354 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1355 { WM_CHILDACTIVATE, sent },
1356 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1357 { WM_MOVE, sent|defwinproc },
1358 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1359 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1360 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1361 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1362 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1363 { WM_GETTEXT, sent|optional },
1364 { 0 }
1365 };
1366 /* repeated ShowWindow(SW_SHOWMINIMIZED) for child with invisible parent */
1367 static const struct message WmShowChildInvisibleParentSeq_3r[] = {
1368 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
1369 { 0 }
1370 };
1371 /* ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1372 static const struct message WmShowChildInvisibleParentSeq_4[] = {
1373 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1374 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
1375 { WM_NCCALCSIZE, sent|wparam, 1 },
1376 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1377 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCOPYBITS|SWP_STATECHANGED },
1378 { WM_MOVE, sent|defwinproc },
1379 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
1380 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1381 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 },
1382 /* FIXME: Wine creates an icon/title window while Windows doesn't */
1383 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE },
1384 { WM_GETTEXT, sent|optional },
1385 { 0 }
1386 };
1387 /* repeated ShowWindow(SW_SHOWMINNOACTIVE) for child with invisible parent */
1388 static const struct message WmShowChildInvisibleParentSeq_4r[] = {
1389 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
1390 { 0 }
1391 };
1392 /* ShowWindow(SW_SHOW) for child with invisible parent */
1393 static const struct message WmShowChildInvisibleParentSeq_5[] = {
1394 { WM_SHOWWINDOW, sent|wparam, 1 },
1395 { 0 }
1396 };
1397 /* ShowWindow(SW_HIDE) for child with invisible parent */
1398 static const struct message WmHideChildInvisibleParentSeq[] = {
1399 { WM_SHOWWINDOW, sent|wparam, 0 },
1400 { 0 }
1401 };
1402 /* SetWindowPos(SWP_SHOWWINDOW) for child with invisible parent */
1403 static const struct message WmShowChildInvisibleParentSeq_6[] = {
1404 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1405 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1406 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1407 { 0 }
1408 };
1409 /* SetWindowPos(SWP_HIDEWINDOW) for child with invisible parent */
1410 static const struct message WmHideChildInvisibleParentSeq_2[] = {
1411 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1412 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1413 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1414 { 0 }
1415 };
1416 /* DestroyWindow for a visible child window */
1417 static const struct message WmDestroyChildSeq[] = {
1418 { HCBT_DESTROYWND, hook },
1419 { 0x0090, sent|optional },
1420 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1421 { WM_SHOWWINDOW, sent|wparam, 0 },
1422 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1423 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1424 { WM_ERASEBKGND, sent|parent|optional },
1425 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1426 { HCBT_SETFOCUS, hook }, /* set focus to a parent */
1427 { WM_KILLFOCUS, sent },
1428 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1429 { WM_IME_SETCONTEXT, sent|wparam|parent|optional, 1 },
1430 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1431 { WM_SETFOCUS, sent|parent },
1432 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1433 { WM_DESTROY, sent },
1434 { WM_DESTROY, sent|optional }, /* some other (IME?) window */
1435 { WM_NCDESTROY, sent|optional }, /* some other (IME?) window */
1436 { WM_NCDESTROY, sent },
1437 { 0 }
1438 };
1439 /* visible child window destroyed by thread exit */
1440 static const struct message WmExitThreadSeq[] = {
1441 { WM_NCDESTROY, sent }, /* actually in grandchild */
1442 { WM_PAINT, sent|parent },
1443 { WM_ERASEBKGND, sent|parent|beginpaint },
1444 { 0 }
1445 };
1446 /* DestroyWindow for a visible child window with invisible parent */
1447 static const struct message WmDestroyInvisibleChildSeq[] = {
1448 { HCBT_DESTROYWND, hook },
1449 { 0x0090, sent|optional },
1450 { WM_PARENTNOTIFY, sent|parent|wparam, WM_DESTROY },
1451 { WM_SHOWWINDOW, sent|wparam, 0 },
1452 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1453 { WM_DESTROY, sent },
1454 { WM_NCDESTROY, sent },
1455 { 0 }
1456 };
1457 /* Resizing child window with MoveWindow (32) */
1458 static const struct message WmResizingChildWithMoveWindowSeq[] = {
1459 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
1460 { WM_NCCALCSIZE, sent|wparam, 1 },
1461 { WM_ERASEBKGND, sent|parent|optional },
1462 { WM_ERASEBKGND, sent|optional },
1463 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE },
1464 { WM_MOVE, sent|defwinproc },
1465 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1466 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1467 { 0 }
1468 };
1469 /* Creation of a custom dialog (32) */
1470 static const struct message WmCreateCustomDialogSeq[] = {
1471 { HCBT_CREATEWND, hook },
1472 { WM_GETMINMAXINFO, sent },
1473 { WM_NCCREATE, sent },
1474 { WM_NCCALCSIZE, sent|wparam, 0 },
1475 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1476 { WM_CREATE, sent },
1477 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1478 { WM_NOTIFYFORMAT, sent|optional },
1479 { WM_QUERYUISTATE, sent|optional },
1480 { WM_WINDOWPOSCHANGING, sent|optional },
1481 { WM_GETMINMAXINFO, sent|optional },
1482 { WM_NCCALCSIZE, sent|optional },
1483 { WM_WINDOWPOSCHANGED, sent|optional },
1484 { WM_SHOWWINDOW, sent|wparam, 1 },
1485 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1486 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1487 { HCBT_ACTIVATE, hook },
1488 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1489
1490
1491 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1492
1493 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1494
1495 { WM_NCACTIVATE, sent },
1496 { WM_GETTEXT, sent|optional|defwinproc },
1497 { WM_GETTEXT, sent|optional|defwinproc },
1498 { WM_GETTEXT, sent|optional|defwinproc },
1499 { EVENT_OBJECT_DEFACTIONCHANGE, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
1500 { WM_ACTIVATE, sent|wparam, 1 },
1501 { WM_GETTEXT, sent|optional },
1502 { WM_KILLFOCUS, sent|parent },
1503 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1504 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1505 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1506 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1507 { WM_SETFOCUS, sent },
1508 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1509 { WM_NCPAINT, sent|wparam, 1 },
1510 { WM_GETTEXT, sent|optional|defwinproc },
1511 { WM_GETTEXT, sent|optional|defwinproc },
1512 { WM_ERASEBKGND, sent },
1513 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1514 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1515 { WM_GETTEXT, sent|optional },
1516 { WM_GETTEXT, sent|optional },
1517 { WM_NCCALCSIZE, sent|optional },
1518 { WM_NCPAINT, sent|optional },
1519 { WM_GETTEXT, sent|optional|defwinproc },
1520 { WM_GETTEXT, sent|optional|defwinproc },
1521 { WM_ERASEBKGND, sent|optional },
1522 { WM_CTLCOLORDLG, sent|optional|defwinproc },
1523 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1524 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1525 { WM_MOVE, sent },
1526 { 0 }
1527 };
1528 /* Calling EndDialog for a custom dialog (32) */
1529 static const struct message WmEndCustomDialogSeq[] = {
1530 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1531 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1532 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1533 { WM_GETTEXT, sent|optional },
1534 { HCBT_ACTIVATE, hook },
1535 { WM_NCACTIVATE, sent|wparam, 0 },
1536 { WM_GETTEXT, sent|optional|defwinproc },
1537 { WM_GETTEXT, sent|optional|defwinproc },
1538 { WM_ACTIVATE, sent|wparam, 0 },
1539 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1540 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1541 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1542 { WM_GETTEXT, sent|optional|defwinproc },
1543 { WM_GETTEXT, sent|optional|defwinproc },
1544 { HCBT_SETFOCUS, hook },
1545 { WM_KILLFOCUS, sent },
1546 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
1547 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1548 { WM_IME_NOTIFY, sent|wparam|optional, 1 },
1549 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1550 { WM_SETFOCUS, sent|parent|defwinproc },
1551 { 0 }
1552 };
1553 /* ShowWindow(SW_SHOW) for a custom dialog (initially invisible) */
1554 static const struct message WmShowCustomDialogSeq[] = {
1555 { WM_SHOWWINDOW, sent|wparam, 1 },
1556 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
1557 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1558 { HCBT_ACTIVATE, hook },
1559 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1560
1561 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1562
1563 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
1564 { WM_ACTIVATEAPP, sent|wparam|optional, 1 },
1565 { WM_NCACTIVATE, sent },
1566 { WM_ACTIVATE, sent|wparam, 1 },
1567 { WM_GETTEXT, sent|optional },
1568
1569 { WM_KILLFOCUS, sent|parent },
1570 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1571 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
1572 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
1573 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1574 { WM_SETFOCUS, sent },
1575 { WM_GETDLGCODE, sent|defwinproc|wparam, 0 },
1576 { WM_NCPAINT, sent|wparam, 1 },
1577 { WM_ERASEBKGND, sent },
1578 { WM_CTLCOLORDLG, sent|defwinproc },
1579 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1580 { 0 }
1581 };
1582 /* Creation and destruction of a modal dialog (32) */
1583 static const struct message WmModalDialogSeq[] = {
1584 { WM_CANCELMODE, sent|parent },
1585 { HCBT_SETFOCUS, hook },
1586 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1587 { WM_KILLFOCUS, sent|parent },
1588 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1589 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1590 { WM_ENABLE, sent|parent|wparam, 0 },
1591 { HCBT_CREATEWND, hook },
1592 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1593 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1594 { WM_SETFONT, sent },
1595 { WM_INITDIALOG, sent },
1596 { WM_CHANGEUISTATE, sent|optional },
1597 { WM_UPDATEUISTATE, sent|optional },
1598 { WM_SHOWWINDOW, sent },
1599 { HCBT_ACTIVATE, hook },
1600 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1601 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
1602 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
1603 { WM_NCACTIVATE, sent },
1604 { WM_GETTEXT, sent|optional },
1605 { WM_ACTIVATE, sent|wparam, 1 },
1606 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1607 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1608 { WM_NCPAINT, sent|optional },
1609 { WM_GETTEXT, sent|optional },
1610 { WM_ERASEBKGND, sent|optional },
1611 { WM_CTLCOLORDLG, sent|optional },
1612 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1613 { WM_GETTEXT, sent|optional },
1614 { WM_NCCALCSIZE, sent|optional },
1615 { WM_NCPAINT, sent|optional },
1616 { WM_GETTEXT, sent|optional },
1617 { WM_ERASEBKGND, sent|optional },
1618 { WM_CTLCOLORDLG, sent|optional },
1619 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1620 { WM_PAINT, sent|optional },
1621 { WM_CTLCOLORBTN, sent|optional },
1622 { WM_GETTITLEBARINFOEX, sent|optional },
1623 { WM_ENTERIDLE, sent|parent|optional },
1624 { WM_ENTERIDLE, sent|parent|optional },
1625 { WM_ENTERIDLE, sent|parent|optional },
1626 { WM_ENTERIDLE, sent|parent|optional },
1627 { WM_ENTERIDLE, sent|parent|optional },
1628 { WM_ENTERIDLE, sent|parent|optional },
1629 { WM_ENTERIDLE, sent|parent|optional },
1630 { WM_ENTERIDLE, sent|parent|optional },
1631 { WM_ENTERIDLE, sent|parent|optional },
1632 { WM_ENTERIDLE, sent|parent|optional },
1633 { WM_ENTERIDLE, sent|parent|optional },
1634 { WM_ENTERIDLE, sent|parent|optional },
1635 { WM_ENTERIDLE, sent|parent|optional },
1636 { WM_ENTERIDLE, sent|parent|optional },
1637 { WM_ENTERIDLE, sent|parent|optional },
1638 { WM_ENTERIDLE, sent|parent|optional },
1639 { WM_ENTERIDLE, sent|parent|optional },
1640 { WM_ENTERIDLE, sent|parent|optional },
1641 { WM_ENTERIDLE, sent|parent|optional },
1642 { WM_ENTERIDLE, sent|parent|optional },
1643 { WM_TIMER, sent },
1644 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1645 { WM_ENABLE, sent|parent|wparam, 1 },
1646 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1647 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1648 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1649 { WM_GETTEXT, sent|optional },
1650 { HCBT_ACTIVATE, hook },
1651 { WM_NCACTIVATE, sent|wparam, 0 },
1652 { WM_GETTEXT, sent|optional },
1653 { WM_ACTIVATE, sent|wparam, 0 },
1654 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
1655 { WM_WINDOWPOSCHANGING, sent|optional },
1656 { WM_WINDOWPOSCHANGED, sent|optional },
1657 { HCBT_SETFOCUS, hook },
1658 { WM_IME_SETCONTEXT, sent|parent|wparam|defwinproc|optional, 1 },
1659 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1660 { WM_SETFOCUS, sent|parent|defwinproc },
1661 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, 0, 0 },
1662 { HCBT_DESTROYWND, hook },
1663 { 0x0090, sent|optional },
1664 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1665 { WM_DESTROY, sent },
1666 { WM_NCDESTROY, sent },
1667 { 0 }
1668 };
1669 static const struct message WmModalDialogSeq_2[] = {
1670 { WM_CANCELMODE, sent },
1671 { HCBT_SETFOCUS, hook },
1672 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
1673 { WM_KILLFOCUS, sent },
1674 { WM_IME_SETCONTEXT, sent|parent|wparam|optional, 0 },
1675 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1676 { WM_ENABLE, sent|wparam, 0 },
1677 { HCBT_CREATEWND, hook },
1678 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1679 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
1680 { WM_SETFONT, sent },
1681 { WM_INITDIALOG, sent },
1682 { WM_CHANGEUISTATE, sent|optional },
1683 { WM_UPDATEUISTATE, sent|optional },
1684 { WM_ENABLE, sent|wparam, 1 },
1685 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1686 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
1687 { WM_CHANGEUISTATE, sent|optional },
1688 { WM_UPDATEUISTATE, sent|optional },
1689 { HCBT_DESTROYWND, hook },
1690 { 0x0090, sent|optional },
1691 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
1692 { WM_DESTROY, sent },
1693 { WM_NCDESTROY, sent },
1694 { 0 }
1695 };
1696 /* SetMenu for NonVisible windows with size change*/
1697 static const struct message WmSetMenuNonVisibleSizeChangeSeq[] = {
1698 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1699 { WM_NCCALCSIZE, sent|wparam, 1 },
1700 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1701 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
1702 { WM_MOVE, sent|defwinproc },
1703 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1704 { WM_NCCALCSIZE,sent|wparam|optional, 1 }, /* XP */
1705 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1706 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1707 { WM_GETTEXT, sent|optional },
1708 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1709 { 0 }
1710 };
1711 /* SetMenu for NonVisible windows with no size change */
1712 static const struct message WmSetMenuNonVisibleNoSizeChangeSeq[] = {
1713 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1714 { WM_NCCALCSIZE, sent|wparam, 1 },
1715 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1716 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1717 { 0 }
1718 };
1719 /* SetMenu for Visible windows with size change */
1720 static const struct message WmSetMenuVisibleSizeChangeSeq[] = {
1721 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1722 { WM_NCCALCSIZE, sent|wparam, 1 },
1723 { 0x0093, sent|defwinproc|optional },
1724 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1725 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1726 { 0x0093, sent|defwinproc|optional },
1727 { 0x0093, sent|defwinproc|optional },
1728 { 0x0091, sent|defwinproc|optional },
1729 { 0x0092, sent|defwinproc|optional },
1730 { WM_GETTEXT, sent|defwinproc|optional },
1731 { WM_ERASEBKGND, sent|optional },
1732 { WM_ACTIVATE, sent|optional },
1733 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1734 { WM_MOVE, sent|defwinproc },
1735 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
1736 { 0x0093, sent|optional },
1737 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1738 { 0x0093, sent|defwinproc|optional },
1739 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1740 { 0x0093, sent|defwinproc|optional },
1741 { 0x0093, sent|defwinproc|optional },
1742 { 0x0091, sent|defwinproc|optional },
1743 { 0x0092, sent|defwinproc|optional },
1744 { WM_ERASEBKGND, sent|optional },
1745 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1746 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP sends a duplicate */
1747 { 0 }
1748 };
1749 /* SetMenu for Visible windows with no size change */
1750 static const struct message WmSetMenuVisibleNoSizeChangeSeq[] = {
1751 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1752 { WM_NCCALCSIZE, sent|wparam, 1 },
1753 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1754 { WM_GETTEXT, sent|defwinproc|optional },
1755 { WM_ERASEBKGND, sent|optional },
1756 { WM_ACTIVATE, sent|optional },
1757 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1758 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1759 { 0 }
1760 };
1761 /* DrawMenuBar for a visible window */
1762 static const struct message WmDrawMenuBarSeq[] =
1763 {
1764 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1765 { WM_NCCALCSIZE, sent|wparam, 1 },
1766 { 0x0093, sent|defwinproc|optional },
1767 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
1768 { 0x0093, sent|defwinproc|optional },
1769 { 0x0093, sent|defwinproc|optional },
1770 { 0x0091, sent|defwinproc|optional },
1771 { 0x0092, sent|defwinproc|optional },
1772 { WM_GETTEXT, sent|defwinproc|optional },
1773 { WM_ERASEBKGND, sent|optional },
1774 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1775 { 0x0093, sent|optional },
1776 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1777 { 0 }
1778 };
1779
1780 static const struct message WmSetRedrawFalseSeq[] =
1781 {
1782 { WM_SETREDRAW, sent|wparam, 0 },
1783 { 0 }
1784 };
1785
1786 static const struct message WmSetRedrawTrueSeq[] =
1787 {
1788 { WM_SETREDRAW, sent|wparam, 1 },
1789 { 0 }
1790 };
1791
1792 static const struct message WmEnableWindowSeq_1[] =
1793 {
1794 { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1795 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1796 { HCBT_SETFOCUS, hook|optional },
1797 { WM_KILLFOCUS, sent|optional },
1798 { WM_ENABLE, sent|wparam|lparam, FALSE, 0 },
1799 { 0 }
1800 };
1801
1802 static const struct message WmEnableWindowSeq_2[] =
1803 {
1804 { WM_CANCELMODE, sent|wparam|lparam, 0, 0 },
1805 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1806 { 0 }
1807 };
1808
1809 static const struct message WmEnableWindowSeq_3[] =
1810 {
1811 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1812 { WM_ENABLE, sent|wparam|lparam, TRUE, 0 },
1813 { 0 }
1814 };
1815
1816 static const struct message WmEnableWindowSeq_4[] =
1817 {
1818 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, 0, 0 },
1819 { 0 }
1820 };
1821
1822 static const struct message WmGetScrollRangeSeq[] =
1823 {
1824 { SBM_GETRANGE, sent },
1825 { 0 }
1826 };
1827 static const struct message WmGetScrollInfoSeq[] =
1828 {
1829 { SBM_GETSCROLLINFO, sent },
1830 { 0 }
1831 };
1832 static const struct message WmSetScrollRangeSeq[] =
1833 {
1834 /* MSDN claims that Windows sends SBM_SETRANGE message, but win2k SP4
1835 sends SBM_SETSCROLLINFO.
1836 */
1837 { SBM_SETSCROLLINFO, sent },
1838 { 0 }
1839 };
1840 /* SetScrollRange for a window without a non-client area */
1841 static const struct message WmSetScrollRangeHSeq_empty[] =
1842 {
1843 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_HSCROLL, 0 },
1844 { 0 }
1845 };
1846 static const struct message WmSetScrollRangeVSeq_empty[] =
1847 {
1848 { EVENT_OBJECT_VALUECHANGE, winevent_hook|wparam|lparam, OBJID_VSCROLL, 0 },
1849 { 0 }
1850 };
1851 static const struct message WmSetScrollRangeHVSeq[] =
1852 {
1853 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1854 { WM_NCCALCSIZE, sent|wparam, 1 },
1855 { WM_GETTEXT, sent|defwinproc|optional },
1856 { WM_ERASEBKGND, sent|optional },
1857 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1858 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1859 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1860 { 0 }
1861 };
1862 /* SetScrollRange for a window with a non-client area */
1863 static const struct message WmSetScrollRangeHV_NC_Seq[] =
1864 {
1865 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE },
1866 { WM_NCCALCSIZE, sent|wparam, 1 },
1867 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
1868 { WM_NCPAINT, sent|optional },
1869 { WM_STYLECHANGING, sent|defwinproc|optional },
1870 { WM_STYLECHANGED, sent|defwinproc|optional },
1871 { WM_STYLECHANGING, sent|defwinproc|optional },
1872 { WM_STYLECHANGED, sent|defwinproc|optional },
1873 { WM_STYLECHANGING, sent|defwinproc|optional },
1874 { WM_STYLECHANGED, sent|defwinproc|optional },
1875 { WM_STYLECHANGING, sent|defwinproc|optional },
1876 { WM_STYLECHANGED, sent|defwinproc|optional },
1877 { WM_GETTEXT, sent|defwinproc|optional },
1878 { WM_GETTEXT, sent|defwinproc|optional },
1879 { WM_ERASEBKGND, sent|optional },
1880 { WM_CTLCOLORDLG, sent|defwinproc|optional }, /* sent to a parent of the dialog */
1881 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOCLIENTSIZE },
1882 { WM_SIZE, sent|defwinproc|optional },
1883 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1884 { EVENT_OBJECT_VALUECHANGE, winevent_hook|lparam|optional, 0/*OBJID_HSCROLL or OBJID_VSCROLL*/, 0 },
1885 { WM_GETTEXT, sent|optional },
1886 { WM_GETTEXT, sent|optional },
1887 { WM_GETTEXT, sent|optional },
1888 { WM_GETTEXT, sent|optional },
1889 { 0 }
1890 };
1891 /* test if we receive the right sequence of messages */
1892 /* after calling ShowWindow( SW_SHOWNA) */
1893 static const struct message WmSHOWNAChildInvisParInvis[] = {
1894 { WM_SHOWWINDOW, sent|wparam, 1 },
1895 { 0 }
1896 };
1897 static const struct message WmSHOWNAChildVisParInvis[] = {
1898 { WM_SHOWWINDOW, sent|wparam, 1 },
1899 { 0 }
1900 };
1901 static const struct message WmSHOWNAChildVisParVis[] = {
1902 { WM_SHOWWINDOW, sent|wparam, 1 },
1903 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1904 { 0 }
1905 };
1906 static const struct message WmSHOWNAChildInvisParVis[] = {
1907 { WM_SHOWWINDOW, sent|wparam, 1 },
1908 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1909 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1910 { WM_ERASEBKGND, sent|optional },
1911 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOACTIVATE|SWP_NOCLIENTMOVE },
1912 { 0 }
1913 };
1914 static const struct message WmSHOWNATopVisible[] = {
1915 { WM_SHOWWINDOW, sent|wparam, 1 },
1916 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
1917 { WM_NCPAINT, sent|wparam|optional, 1 },
1918 { WM_GETTEXT, sent|defwinproc|optional },
1919 { WM_ERASEBKGND, sent|optional },
1920 { WM_WINDOWPOSCHANGED, sent|optional },
1921 { 0 }
1922 };
1923 static const struct message WmSHOWNATopInvisible[] = {
1924 { WM_NOTIFYFORMAT, sent|optional },
1925 { WM_QUERYUISTATE, sent|optional },
1926 { WM_WINDOWPOSCHANGING, sent|optional },
1927 { WM_GETMINMAXINFO, sent|optional },
1928 { WM_NCCALCSIZE, sent|optional },
1929 { WM_WINDOWPOSCHANGED, sent|optional },
1930 { WM_SHOWWINDOW, sent|wparam, 1 },
1931 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
1932 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
1933 { WM_NCPAINT, sent|wparam|optional, 1 },
1934 { WM_GETTEXT, sent|defwinproc|optional },
1935 { WM_ERASEBKGND, sent|optional },
1936 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
1937 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
1938 { WM_NCPAINT, sent|wparam|optional, 1 },
1939 { WM_ERASEBKGND, sent|optional },
1940 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
1941 { WM_SIZE, sent|wparam, SIZE_RESTORED },
1942 { WM_MOVE, sent },
1943 { 0 }
1944 };
1945
1946 static const struct message WmTrackPopupMenu[] = {
1947 { HCBT_CREATEWND, hook },
1948 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1949 { WM_INITMENU, sent|lparam, 0, 0 },
1950 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1951 { 0x0093, sent|optional },
1952 { 0x0094, sent|optional },
1953 { 0x0094, sent|optional },
1954 { WM_ENTERIDLE, sent|wparam, 2 },
1955 { WM_CAPTURECHANGED, sent },
1956 { HCBT_DESTROYWND, hook },
1957 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1958 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1959 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1960 { 0 }
1961 };
1962
1963 static const struct message WmTrackPopupMenuEsc[] = {
1964 { 0 }
1965 };
1966
1967 static const struct message WmTrackPopupMenuCapture[] = {
1968 { HCBT_CREATEWND, hook },
1969 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1970 { WM_CAPTURECHANGED, sent },
1971 { WM_INITMENU, sent|lparam, 0, 0 },
1972 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1973 { 0x0093, sent|optional },
1974 { 0x0094, sent|optional },
1975 { 0x0094, sent|optional },
1976 { WM_ENTERIDLE, sent|wparam, 2 },
1977 { WM_CAPTURECHANGED, sent },
1978 { HCBT_DESTROYWND, hook },
1979 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1980 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
1981 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1982 { 0 }
1983 };
1984
1985 static const struct message WmTrackPopupMenuEmpty[] = {
1986 { HCBT_CREATEWND, hook },
1987 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
1988 { WM_INITMENU, sent|lparam, 0, 0 },
1989 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
1990 { 0x0093, sent|optional },
1991 { 0x0094, sent|optional },
1992 { 0x0094, sent|optional },
1993 { WM_CAPTURECHANGED, sent },
1994 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
1995 { HCBT_DESTROYWND, hook },
1996 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
1997 { 0 }
1998 };
1999
2000 static const struct message WmTrackPopupMenuAbort[] = {
2001 { HCBT_CREATEWND, hook },
2002 { WM_ENTERMENULOOP, sent|wparam|lparam, TRUE, 0 },
2003 { WM_INITMENU, sent|lparam, 0, 0 },
2004 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
2005 { 0x0093, sent|optional },
2006 { 0x0094, sent|optional },
2007 { 0x0094, sent|optional },
2008 { WM_CAPTURECHANGED, sent },
2009 { HCBT_DESTROYWND, hook },
2010 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
2011 { WM_MENUSELECT, sent|wparam|lparam, 0xffff0000, 0 },
2012 { WM_EXITMENULOOP, sent|wparam|lparam, 1, 0 },
2013 { 0 }
2014 };
2015
2016 static BOOL after_end_dialog, test_def_id, paint_loop_done;
2017 static int sequence_cnt, sequence_size;
2018 static struct recvd_message* sequence;
2019 static int log_all_parent_messages;
2020 static CRITICAL_SECTION sequence_cs;
2021
2022 /* user32 functions */
2023 static HWND (WINAPI *pGetAncestor)(HWND,UINT);
2024 static BOOL (WINAPI *pGetMenuInfo)(HMENU,LPCMENUINFO);
2025 static void (WINAPI *pNotifyWinEvent)(DWORD, HWND, LONG, LONG);
2026 static BOOL (WINAPI *pSetMenuInfo)(HMENU,LPCMENUINFO);
2027 static HWINEVENTHOOK (WINAPI *pSetWinEventHook)(DWORD, DWORD, HMODULE, WINEVENTPROC, DWORD, DWORD, DWORD);
2028 static BOOL (WINAPI *pTrackMouseEvent)(TRACKMOUSEEVENT*);
2029 static BOOL (WINAPI *pUnhookWinEvent)(HWINEVENTHOOK);
2030 static BOOL (WINAPI *pGetMonitorInfoA)(HMONITOR,LPMONITORINFO);
2031 static HMONITOR (WINAPI *pMonitorFromPoint)(POINT,DWORD);
2032 static BOOL (WINAPI *pUpdateLayeredWindow)(HWND,HDC,POINT*,SIZE*,HDC,POINT*,COLORREF,BLENDFUNCTION*,DWORD);
2033 static UINT_PTR (WINAPI *pSetSystemTimer)(HWND, UINT_PTR, UINT, TIMERPROC);
2034 static UINT_PTR (WINAPI *pKillSystemTimer)(HWND, UINT_PTR);
2035 static UINT_PTR (WINAPI *pSetCoalescableTimer)(HWND, UINT_PTR, UINT, TIMERPROC, ULONG);
2036 /* kernel32 functions */
2037 static BOOL (WINAPI *pGetCPInfoExA)(UINT, DWORD, LPCPINFOEXA);
2038
2039 static void init_procs(void)
2040 {
2041 HMODULE user32 = GetModuleHandleA("user32.dll");
2042 HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
2043
2044 #define GET_PROC(dll, func) \
2045 p ## func = (void*)GetProcAddress(dll, #func); \
2046 if(!p ## func) { \
2047 trace("GetProcAddress(%s) failed\n", #func); \
2048 }
2049
2050 GET_PROC(user32, GetAncestor)
2051 GET_PROC(user32, GetMenuInfo)
2052 GET_PROC(user32, NotifyWinEvent)
2053 GET_PROC(user32, SetMenuInfo)
2054 GET_PROC(user32, SetWinEventHook)
2055 GET_PROC(user32, TrackMouseEvent)
2056 GET_PROC(user32, UnhookWinEvent)
2057 GET_PROC(user32, GetMonitorInfoA)
2058 GET_PROC(user32, MonitorFromPoint)
2059 GET_PROC(user32, UpdateLayeredWindow)
2060 GET_PROC(user32, SetSystemTimer)
2061 GET_PROC(user32, KillSystemTimer)
2062 GET_PROC(user32, SetCoalescableTimer)
2063
2064 GET_PROC(kernel32, GetCPInfoExA)
2065
2066 #undef GET_PROC
2067 }
2068
2069 static const char *get_winpos_flags(UINT flags)
2070 {
2071 static char buffer[300];
2072
2073 buffer[0] = 0;
2074 #define DUMP(flag) do { if (flags & flag) { strcat( buffer, "|" #flag ); flags &= ~flag; } } while(0)
2075 DUMP( SWP_SHOWWINDOW );
2076 DUMP( SWP_HIDEWINDOW );
2077 DUMP( SWP_NOACTIVATE );
2078 DUMP( SWP_FRAMECHANGED );
2079 DUMP( SWP_NOCOPYBITS );
2080 DUMP( SWP_NOOWNERZORDER );
2081 DUMP( SWP_NOSENDCHANGING );
2082 DUMP( SWP_DEFERERASE );
2083 DUMP( SWP_ASYNCWINDOWPOS );
2084 DUMP( SWP_NOZORDER );
2085 DUMP( SWP_NOREDRAW );
2086 DUMP( SWP_NOSIZE );
2087 DUMP( SWP_NOMOVE );
2088 DUMP( SWP_NOCLIENTSIZE );
2089 DUMP( SWP_NOCLIENTMOVE );
2090 if (flags) sprintf(buffer + strlen(buffer),"|0x%04x", flags);
2091 return buffer + 1;
2092 #undef DUMP
2093 }
2094
2095 static BOOL ignore_message( UINT message )
2096 {
2097 /* these are always ignored */
2098 return (message >= 0xc000 ||
2099 message == WM_GETICON ||
2100 message == WM_GETOBJECT ||
2101 message == WM_TIMECHANGE ||
2102 message == WM_DISPLAYCHANGE ||
2103 message == WM_DEVICECHANGE ||
2104 message == WM_DWMNCRENDERINGCHANGED);
2105 }
2106
2107 static unsigned hash_Ly_W(const WCHAR *str)
2108 {
2109 unsigned hash = 0;
2110
2111 for (; *str; str++)
2112 hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
2113
2114 return hash;
2115 }
2116
2117 static unsigned hash_Ly(const char *str)
2118 {
2119 unsigned hash = 0;
2120
2121 for (; *str; str++)
2122 hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
2123
2124 return hash;
2125 }
2126
2127 #define add_message(msg) add_message_(__LINE__,msg);
2128 static void add_message_(int line, const struct recvd_message *msg)
2129 {
2130 struct recvd_message *seq;
2131
2132 EnterCriticalSection( &sequence_cs );
2133 if (!sequence)
2134 {
2135 sequence_size = 10;
2136 sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof(*sequence) );
2137 }
2138 if (sequence_cnt == sequence_size)
2139 {
2140 sequence_size *= 2;
2141 sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof(*sequence) );
2142 }
2143 assert(sequence);
2144
2145 seq = &sequence[sequence_cnt++];
2146 seq->hwnd = msg->hwnd;
2147 seq->message = msg->message;
2148 seq->flags = msg->flags;
2149 seq->wParam = msg->wParam;
2150 seq->lParam = msg->lParam;
2151 seq->line = line;
2152 seq->descr = msg->descr;
2153 seq->output[0] = 0;
2154 LeaveCriticalSection( &sequence_cs );
2155
2156 if (msg->descr)
2157 {
2158 if (msg->flags & hook)
2159 {
2160 static const char * const CBT_code_name[10] =
2161 {
2162 "HCBT_MOVESIZE",
2163 "HCBT_MINMAX",
2164 "HCBT_QS",
2165 "HCBT_CREATEWND",
2166 "HCBT_DESTROYWND",
2167 "HCBT_ACTIVATE",
2168 "HCBT_CLICKSKIPPED",
2169 "HCBT_KEYSKIPPED",
2170 "HCBT_SYSCOMMAND",
2171 "HCBT_SETFOCUS"
2172 };
2173 const char *code_name = (msg->message <= HCBT_SETFOCUS) ? CBT_code_name[msg->message] : "Unknown";
2174
2175 sprintf( seq->output, "%s: hook %d (%s) wp %08lx lp %08lx",
2176 msg->descr, msg->message, code_name, msg->wParam, msg->lParam );
2177 }
2178 else if (msg->flags & winevent_hook)
2179 {
2180 sprintf( seq->output, "%s: winevent %p %08x %08lx %08lx",
2181 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2182 }
2183 else
2184 {
2185 switch (msg->message)
2186 {
2187 case WM_WINDOWPOSCHANGING:
2188 case WM_WINDOWPOSCHANGED:
2189 {
2190 WINDOWPOS *winpos = (WINDOWPOS *)msg->lParam;
2191
2192 sprintf( seq->output, "%s: %p WM_WINDOWPOS%s wp %08lx lp %08lx after %p x %d y %d cx %d cy %d flags %s",
2193 msg->descr, msg->hwnd,
2194 (msg->message == WM_WINDOWPOSCHANGING) ? "CHANGING" : "CHANGED",
2195 msg->wParam, msg->lParam, winpos->hwndInsertAfter,
2196 winpos->x, winpos->y, winpos->cx, winpos->cy,
2197 get_winpos_flags(winpos->flags) );
2198
2199 /* Log only documented flags, win2k uses 0x1000 and 0x2000
2200 * in the high word for internal purposes
2201 */
2202 seq->wParam = winpos->flags & 0xffff;
2203 /* We are not interested in the flags that don't match under XP and Win9x */
2204 seq->wParam &= ~SWP_NOZORDER;
2205 break;
2206 }
2207
2208 case WM_DRAWITEM:
2209 {
2210 DRAW_ITEM_STRUCT di;
2211 DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)msg->lParam;
2212
2213 sprintf( seq->output, "%s: %p WM_DRAWITEM: type %x, ctl_id %x, item_id %x, action %x, state %x",
2214 msg->descr, msg->hwnd, dis->CtlType, dis->CtlID,
2215 dis->itemID, dis->itemAction, dis->itemState);
2216
2217 di.u.lp = 0;
2218 di.u.item.type = dis->CtlType;
2219 di.u.item.ctl_id = dis->CtlID;
2220 if (dis->CtlType == ODT_LISTBOX ||
2221 dis->CtlType == ODT_COMBOBOX ||
2222 dis->CtlType == ODT_MENU)
2223 di.u.item.item_id = dis->itemID;
2224 di.u.item.action = dis->itemAction;
2225 di.u.item.state = dis->itemState;
2226
2227 seq->lParam = di.u.lp;
2228 break;
2229 }
2230
2231 case WM_MEASUREITEM:
2232 {
2233 MEASURE_ITEM_STRUCT mi;
2234 MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)msg->lParam;
2235 BOOL is_unicode_data = TRUE;
2236
2237 sprintf( seq->output, "%s: %p WM_MEASUREITEM: CtlType %#x, CtlID %#x, itemID %#x, itemData %#lx",
2238 msg->descr, msg->hwnd, mis->CtlType, mis->CtlID,
2239 mis->itemID, mis->itemData);
2240
2241 if (mis->CtlType == ODT_LISTBOX)
2242 {
2243 HWND ctrl = GetDlgItem(msg->hwnd, mis->CtlID);
2244 is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
2245 }
2246
2247 mi.u.wp = 0;
2248 mi.u.item.CtlType = mis->CtlType;
2249 mi.u.item.CtlID = mis->CtlID;
2250 mi.u.item.itemID = mis->itemID;
2251 mi.u.item.wParam = msg->wParam;
2252 seq->wParam = mi.u.wp;
2253 if (is_unicode_data)
2254 seq->lParam = mis->itemData ? hash_Ly_W((const WCHAR *)mis->itemData) : 0;
2255 else
2256 seq->lParam = mis->itemData ? hash_Ly((const char *)mis->itemData) : 0;
2257 break;
2258 }
2259
2260 case WM_COMPAREITEM:
2261 {
2262 COMPAREITEMSTRUCT *cis = (COMPAREITEMSTRUCT *)msg->lParam;
2263 HWND ctrl = GetDlgItem(msg->hwnd, cis->CtlID);
2264 BOOL is_unicode_data = TRUE;
2265
2266 ok(msg->wParam == cis->CtlID, "expected %#x, got %#lx\n", cis->CtlID, msg->wParam);
2267 ok(cis->hwndItem == ctrl, "expected %p, got %p\n", ctrl, cis->hwndItem);
2268 ok((int)cis->itemID1 >= 0, "expected >= 0, got %d\n", cis->itemID1);
2269 ok((int)cis->itemID2 == -1, "expected -1, got %d\n", cis->itemID2);
2270
2271 sprintf( seq->output, "%s: %p WM_COMPAREITEM: CtlType %#x, CtlID %#x, itemID1 %#x, itemData1 %#lx, itemID2 %#x, itemData2 %#lx",
2272 msg->descr, msg->hwnd, cis->CtlType, cis->CtlID,
2273 cis->itemID1, cis->itemData1, cis->itemID2, cis->itemData2);
2274
2275 if (cis->CtlType == ODT_LISTBOX)
2276 is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
2277
2278 if (is_unicode_data)
2279 {
2280 seq->wParam = cis->itemData1 ? hash_Ly_W((const WCHAR *)cis->itemData1) : 0;
2281 seq->lParam = cis->itemData2 ? hash_Ly_W((const WCHAR *)cis->itemData2) : 0;
2282 }
2283 else
2284 {
2285 seq->wParam = cis->itemData1 ? hash_Ly((const char *)cis->itemData1) : 0;
2286 seq->lParam = cis->itemData2 ? hash_Ly((const char *)cis->itemData2) : 0;
2287 }
2288 break;
2289 }
2290
2291 default:
2292 if (msg->message >= 0xc000) return; /* ignore registered messages */
2293 sprintf( seq->output, "%s: %p %04x wp %08lx lp %08lx",
2294 msg->descr, msg->hwnd, msg->message, msg->wParam, msg->lParam );
2295 }
2296 if (msg->flags & (sent|posted|parent|defwinproc|beginpaint))
2297 sprintf( seq->output + strlen(seq->output), " (flags %x)", msg->flags );
2298 }
2299 }
2300 }
2301
2302 /* try to make sure pending X events have been processed before continuing */
2303 static void flush_events(void)
2304 {
2305 MSG msg;
2306 int diff = 200;
2307 int min_timeout = 100;
2308 DWORD time = GetTickCount() + diff;
2309
2310 while (diff > 0)
2311 {
2312 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
2313 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
2314 diff = time - GetTickCount();
2315 }
2316 }
2317
2318 static void flush_sequence(void)
2319 {
2320 EnterCriticalSection( &sequence_cs );
2321 HeapFree(GetProcessHeap(), 0, sequence);
2322 sequence = 0;
2323 sequence_cnt = sequence_size = 0;
2324 LeaveCriticalSection( &sequence_cs );
2325 }
2326
2327 static void dump_sequence(const struct message *expected, const char *context, const char *file, int line)
2328 {
2329 const struct recvd_message *actual = sequence;
2330 unsigned int count = 0;
2331
2332 trace_(file, line)("Failed sequence %s:\n", context );
2333 while (expected->message && actual->message)
2334 {
2335 if (actual->output[0])
2336 {
2337 if (expected->flags & hook)
2338 {
2339 trace_(file, line)( " %u: expected: hook %04x - actual: %s\n",
2340 count, expected->message, actual->output );
2341 }
2342 else if (expected->flags & winevent_hook)
2343 {
2344 trace_(file, line)( " %u: expected: winevent %04x - actual: %s\n",
2345 count, expected->message, actual->output );
2346 }
2347 else if (expected->flags & kbd_hook)
2348 {
2349 trace_(file, line)( " %u: expected: kbd %04x - actual: %s\n",
2350 count, expected->message, actual->output );
2351 }
2352 else
2353 {
2354 trace_(file, line)( " %u: expected: msg %04x - actual: %s\n",
2355 count, expected->message, actual->output );
2356 }
2357 }
2358
2359 if (expected->message == actual->message)
2360 {
2361 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) &&
2362 (expected->flags & optional))
2363 {
2364 /* don't match messages if their defwinproc status differs */
2365 expected++;
2366 }
2367 else
2368 {
2369 expected++;
2370 actual++;
2371 }
2372 }
2373 /* silently drop winevent messages if there is no support for them */
2374 else if ((expected->flags & optional) || ((expected->flags & winevent_hook) && !hEvent_hook))
2375 expected++;
2376 else
2377 {
2378 expected++;
2379 actual++;
2380 }
2381 count++;
2382 }
2383
2384 /* optional trailing messages */
2385 while (expected->message && ((expected->flags & optional) ||
2386 ((expected->flags & winevent_hook) && !hEvent_hook)))
2387 {
2388 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2389 expected++;
2390 count++;
2391 }
2392
2393 if (expected->message)
2394 {
2395 trace_(file, line)( " %u: expected: msg %04x - actual: nothing\n", count, expected->message );
2396 return;
2397 }
2398
2399 while (actual->message && actual->output[0])
2400 {
2401 trace_(file, line)( " %u: expected: nothing - actual: %s\n", count, actual->output );
2402 actual++;
2403 count++;
2404 }
2405 }
2406
2407 #define ok_sequence( exp, contx, todo) \
2408 ok_sequence_( (exp), (contx), (todo), __FILE__, __LINE__)
2409
2410
2411 static void ok_sequence_(const struct message *expected_list, const char *context, BOOL todo,
2412 const char *file, int line)
2413 {
2414 static const struct recvd_message end_of_sequence;
2415 const struct message *expected = expected_list;
2416 const struct recvd_message *actual;
2417 int failcount = 0, dump = 0;
2418 unsigned int count = 0;
2419
2420 add_message(&end_of_sequence);
2421
2422 actual = sequence;
2423
2424 while (expected->message && actual->message)
2425 {
2426 if (expected->message == actual->message &&
2427 !((expected->flags ^ actual->flags) & (hook|winevent_hook|kbd_hook)))
2428 {
2429 if (expected->flags & wparam)
2430 {
2431 if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo)
2432 {
2433 todo_wine {
2434 failcount ++;
2435 if (strcmp(winetest_platform, "wine")) dump++;
2436 ok_( file, line) (FALSE,
2437 "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2438 context, count, expected->message, expected->wParam, actual->wParam);
2439 }
2440 }
2441 else
2442 {
2443 ok_( file, line)( ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) == 0,
2444 "%s: %u: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n",
2445 context, count, expected->message, expected->wParam, actual->wParam);
2446 if ((expected->wParam ^ actual->wParam) & ~expected->wp_mask) dump++;
2447 }
2448
2449 }
2450 if (expected->flags & lparam)
2451 {
2452 if (((expected->lParam ^ actual->lParam) & ~expected->lp_mask) && todo)
2453 {
2454 todo_wine {
2455 failcount ++;
2456 if (strcmp(winetest_platform, "wine")) dump++;
2457 ok_( file, line) (FALSE,
2458 "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2459 context, count, expected->message, expected->lParam, actual->lParam);
2460 }
2461 }
2462 else
2463 {
2464 ok_( file, line)(((expected->lParam ^ actual->lParam) & ~expected->lp_mask) == 0,
2465 "%s: %u: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n",
2466 context, count, expected->message, expected->lParam, actual->lParam);
2467 if ((expected->lParam ^ actual->lParam) & ~expected->lp_mask) dump++;
2468 }
2469 }
2470 if ((expected->flags & optional) &&
2471 ((expected->flags ^ actual->flags) & (defwinproc|parent)))
2472 {
2473 /* don't match optional messages if their defwinproc or parent status differs */
2474 expected++;
2475 count++;
2476 continue;
2477 }
2478 if ((expected->flags & defwinproc) != (actual->flags & defwinproc) && todo)
2479 {
2480 todo_wine {
2481 failcount ++;
2482 if (strcmp(winetest_platform, "wine")) dump++;
2483 ok_( file, line) (FALSE,
2484 "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2485 context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2486 }
2487 }
2488 else
2489 {
2490 ok_( file, line) ((expected->flags & defwinproc) == (actual->flags & defwinproc),
2491 "%s: %u: the msg 0x%04x should %shave been sent by DefWindowProc\n",
2492 context, count, expected->message, (expected->flags & defwinproc) ? "" : "NOT ");
2493 if ((expected->flags & defwinproc) != (actual->flags & defwinproc)) dump++;
2494 }
2495
2496 ok_( file, line) ((expected->flags & beginpaint) == (actual->flags & beginpaint),
2497 "%s: %u: the msg 0x%04x should %shave been sent by BeginPaint\n",
2498 context, count, expected->message, (expected->flags & beginpaint) ? "" : "NOT ");
2499 if ((expected->flags & beginpaint) != (actual->flags & beginpaint)) dump++;
2500
2501 ok_( file, line) ((expected->flags & (sent|posted)) == (actual->flags & (sent|posted)),
2502 "%s: %u: the msg 0x%04x should have been %s\n",
2503 context, count, expected->message, (expected->flags & posted) ? "posted" : "sent");
2504 if ((expected->flags & (sent|posted)) != (actual->flags & (sent|posted))) dump++;
2505
2506 ok_( file, line) ((expected->flags & parent) == (actual->flags & parent),
2507 "%s: %u: the msg 0x%04x was expected in %s\n",
2508 context, count, expected->message, (expected->flags & parent) ? "parent" : "child");
2509 if ((expected->flags & parent) != (actual->flags & parent)) dump++;
2510
2511 ok_( file, line) ((expected->flags & hook) == (actual->flags & hook),
2512 "%s: %u: the msg 0x%04x should have been sent by a hook\n",
2513 context, count, expected->message);
2514 if ((expected->flags & hook) != (actual->flags & hook)) dump++;
2515
2516 ok_( file, line) ((expected->flags & winevent_hook) == (actual->flags & winevent_hook),
2517 "%s: %u: the msg 0x%04x should have been sent by a winevent hook\n",
2518 context, count, expected->message);
2519 if ((expected->flags & winevent_hook) != (actual->flags & winevent_hook)) dump++;
2520
2521 ok_( file, line) ((expected->flags & kbd_hook) == (actual->flags & kbd_hook),
2522 "%s: %u: the msg 0x%04x should have been sent by a keyboard hook\n",
2523 context, count, expected->message);
2524 if ((expected->flags & kbd_hook) != (actual->flags & kbd_hook)) dump++;
2525
2526 expected++;
2527 actual++;
2528 }
2529 /* silently drop hook messages if there is no support for them */
2530 else if ((expected->flags & optional) ||
2531 ((expected->flags & hook) && !hCBT_hook) ||
2532 ((expected->flags & winevent_hook) && !hEvent_hook) ||
2533 ((expected->flags & kbd_hook) && !hKBD_hook))
2534 expected++;
2535 else if (todo)
2536 {
2537 failcount++;
2538 todo_wine {
2539 if (strcmp(winetest_platform, "wine")) dump++;
2540 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2541 context, count, expected->message, actual->message);
2542 }
2543 goto done;
2544 }
2545 else
2546 {
2547 ok_( file, line) (FALSE, "%s: %u: the msg 0x%04x was expected, but got msg 0x%04x instead\n",
2548 context, count, expected->message, actual->message);
2549 dump++;
2550 expected++;
2551 actual++;
2552 }
2553 count++;
2554 }
2555
2556 /* skip all optional trailing messages */
2557 while (expected->message && ((expected->flags & optional) ||
2558 ((expected->flags & hook) && !hCBT_hook) ||
2559 ((expected->flags & winevent_hook) && !hEvent_hook)))
2560 expected++;
2561
2562 if (todo)
2563 {
2564 todo_wine {
2565 if (expected->message || actual->message) {
2566 failcount++;
2567 if (strcmp(winetest_platform, "wine")) dump++;
2568 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2569 context, count, expected->message, actual->message);
2570 }
2571 }
2572 }
2573 else
2574 {
2575 if (expected->message || actual->message)
2576 {
2577 dump++;
2578 ok_( file, line) (FALSE, "%s: %u: the msg sequence is not complete: expected %04x - actual %04x\n",
2579 context, count, expected->message, actual->message);
2580 }
2581 }
2582 if( todo && !failcount) /* succeeded yet marked todo */
2583 todo_wine {
2584 if (!strcmp(winetest_platform, "wine")) dump++;
2585 ok_( file, line)( TRUE, "%s: marked \"todo_wine\" but succeeds\n", context);
2586 }
2587
2588 done:
2589 if (dump) dump_sequence(expected_list, context, file, line);
2590 flush_sequence();
2591 }
2592
2593 #define expect(EXPECTED,GOT) ok((GOT)==(EXPECTED), "Expected %d, got %d\n", (EXPECTED), (GOT))
2594
2595 /******************************** MDI test **********************************/
2596
2597 /* CreateWindow for MDI frame window, initially visible */
2598 static const struct message WmCreateMDIframeSeq[] = {
2599 { HCBT_CREATEWND, hook },
2600 { WM_GETMINMAXINFO, sent },
2601 { WM_NCCREATE, sent },
2602 { WM_NCCALCSIZE, sent|wparam, 0 },
2603 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
2604 { WM_CREATE, sent },
2605 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2606 { WM_NOTIFYFORMAT, sent|optional },
2607 { WM_QUERYUISTATE, sent|optional },
2608 { WM_WINDOWPOSCHANGING, sent|optional },
2609 { WM_GETMINMAXINFO, sent|optional },
2610 { WM_NCCALCSIZE, sent|optional },
2611 { WM_WINDOWPOSCHANGED, sent|optional },
2612 { WM_SHOWWINDOW, sent|wparam, 1 },
2613 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2614 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2615 { HCBT_ACTIVATE, hook },
2616 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
2617 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
2618 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* XP */
2619 { WM_ACTIVATEAPP, sent|wparam|optional, 1 }, /* Win9x doesn't send it */
2620 { WM_NCACTIVATE, sent },
2621 { WM_GETTEXT, sent|defwinproc|optional },
2622 { WM_ACTIVATE, sent|wparam, 1 },
2623 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* Win9x */
2624 { HCBT_SETFOCUS, hook },
2625 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2626 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
2627 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2628 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
2629 /* Win9x adds SWP_NOZORDER below */
2630 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2631 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
2632 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
2633 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2634 { WM_MOVE, sent },
2635 { 0 }
2636 };
2637 /* DestroyWindow for MDI frame window, initially visible */
2638 static const struct message WmDestroyMDIframeSeq[] = {
2639 { HCBT_DESTROYWND, hook },
2640 { 0x0090, sent|optional },
2641 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2642 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2643 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2644 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2645 { WM_NCACTIVATE, sent|wparam|optional, 0 }, /* XP */
2646 { WM_ACTIVATE, sent|wparam|optional, 0 }, /* Win9x */
2647 { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, /* Win9x */
2648 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
2649 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2650 { WM_DESTROY, sent },
2651 { WM_NCDESTROY, sent },
2652 { 0 }
2653 };
2654 /* CreateWindow for MDI client window, initially visible */
2655 static const struct message WmCreateMDIclientSeq[] = {
2656 { HCBT_CREATEWND, hook },
2657 { WM_NCCREATE, sent },
2658 { WM_NCCALCSIZE, sent|wparam, 0 },
2659 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2660 { WM_CREATE, sent },
2661 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2662 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2663 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2664 { WM_MOVE, sent },
2665 { WM_PARENTNOTIFY, sent|wparam, WM_CREATE }, /* in MDI frame */
2666 { WM_SHOWWINDOW, sent|wparam, 1 },
2667 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2668 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2669 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2670 { 0 }
2671 };
2672 /* ShowWindow(SW_SHOW) for MDI client window */
2673 static const struct message WmShowMDIclientSeq[] = {
2674 { WM_SHOWWINDOW, sent|wparam, 1 },
2675 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2676 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2677 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2678 { 0 }
2679 };
2680 /* ShowWindow(SW_HIDE) for MDI client window */
2681 static const struct message WmHideMDIclientSeq[] = {
2682 { WM_SHOWWINDOW, sent|wparam, 0 },
2683 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2684 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* win2000 */
2685 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP */
2686 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2687 { 0 }
2688 };
2689 /* DestroyWindow for MDI client window, initially visible */
2690 static const struct message WmDestroyMDIclientSeq[] = {
2691 { HCBT_DESTROYWND, hook },
2692 { 0x0090, sent|optional },
2693 { WM_PARENTNOTIFY, sent|wparam, WM_DESTROY }, /* in MDI frame */
2694 { WM_SHOWWINDOW, sent|wparam, 0 },
2695 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2696 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2697 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2698 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2699 { WM_DESTROY, sent },
2700 { WM_NCDESTROY, sent },
2701 { 0 }
2702 };
2703 /* CreateWindow for MDI child window, initially visible */
2704 static const struct message WmCreateMDIchildVisibleSeq[] = {
2705 { HCBT_CREATEWND, hook },
2706 { WM_NCCREATE, sent },
2707 { WM_NCCALCSIZE, sent|wparam, 0 },
2708 { WM_CREATE, sent },
2709 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2710 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2711 { WM_MOVE, sent },
2712 /* Win2k sends wparam set to
2713 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2714 * while Win9x doesn't bother to set child window id according to
2715 * CLIENTCREATESTRUCT.idFirstChild
2716 */
2717 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2718 { WM_SHOWWINDOW, sent|wparam, 1 },
2719 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2720 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2721 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2722 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2723 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2724 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2725 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2726
2727 /* Win9x: message sequence terminates here. */
2728
2729 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2730 { HCBT_SETFOCUS, hook }, /* in MDI client */
2731 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2732 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2733 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2734 { WM_SETFOCUS, sent }, /* in MDI client */
2735 { HCBT_SETFOCUS, hook },
2736 { WM_KILLFOCUS, sent }, /* in MDI client */
2737 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2738 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2739 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2740 { WM_SETFOCUS, sent|defwinproc },
2741 { WM_MDIACTIVATE, sent|defwinproc },
2742 { 0 }
2743 };
2744 /* WM_CHILDACTIVATE sent to disabled window */
2745 static const struct message WmChildActivateDisabledWindowSeq[] = {
2746 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2747 { 0 }
2748 };
2749 /* WM_CHILDACTIVATE sent to enabled window */
2750 static const struct message WmChildActivateWindowSeq[] = {
2751 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2752 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 },
2753 { WM_MDIACTIVATE, sent|defwinproc },
2754 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2755 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2756 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2757 { HCBT_SETFOCUS, hook },
2758 { WM_KILLFOCUS, sent|defwinproc },
2759 { WM_SETFOCUS, sent },
2760 { HCBT_SETFOCUS, hook },
2761 { WM_KILLFOCUS, sent },
2762 { WM_SETFOCUS, sent|defwinproc },
2763 { WM_MDIACTIVATE, sent|defwinproc },
2764 { 0 }
2765 };
2766 /* CreateWindow for MDI child window with invisible parent */
2767 static const struct message WmCreateMDIchildInvisibleParentSeq[] = {
2768 { HCBT_CREATEWND, hook },
2769 { WM_GETMINMAXINFO, sent },
2770 { WM_NCCREATE, sent },
2771 { WM_NCCALCSIZE, sent|wparam, 0 },
2772 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|optional, 0, 0 },
2773 { WM_CREATE, sent },
2774 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2775 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2776 { WM_MOVE, sent },
2777 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2778 { WM_SHOWWINDOW, sent|wparam, 1 },
2779 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
2780 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2781 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2782 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2783
2784 /* Win9x: message sequence terminates here. */
2785
2786 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
2787 { HCBT_SETFOCUS, hook }, /* in MDI client */
2788 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2789 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2790 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2791 { WM_SETFOCUS, sent }, /* in MDI client */
2792 { HCBT_SETFOCUS, hook },
2793 { WM_KILLFOCUS, sent }, /* in MDI client */
2794 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2795 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2796 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2797 { WM_SETFOCUS, sent|defwinproc },
2798 { WM_MDIACTIVATE, sent|defwinproc },
2799 { 0 }
2800 };
2801 /* DestroyWindow for MDI child window, initially visible */
2802 static const struct message WmDestroyMDIchildVisibleSeq[] = {
2803 { HCBT_DESTROYWND, hook },
2804 /* Win2k sends wparam set to
2805 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2806 * while Win9x doesn't bother to set child window id according to
2807 * CLIENTCREATESTRUCT.idFirstChild
2808 */
2809 { 0x0090, sent|optional },
2810 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2811 { WM_SHOWWINDOW, sent|wparam, 0 },
2812 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2813 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
2814 { WM_ERASEBKGND, sent|parent|optional },
2815 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2816
2817 /* { WM_DESTROY, sent }
2818 * Win9x: message sequence terminates here.
2819 */
2820
2821 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2822 { WM_KILLFOCUS, sent },
2823 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2824 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2825 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2826 { WM_SETFOCUS, sent }, /* in MDI client */
2827
2828 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2829 { WM_KILLFOCUS, sent }, /* in MDI client */
2830 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2831 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2832 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2833 { WM_SETFOCUS, sent }, /* in MDI client */
2834
2835 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2836
2837 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2838 { WM_KILLFOCUS, sent },
2839 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2840 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2841 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2842 { WM_SETFOCUS, sent }, /* in MDI client */
2843
2844 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2845 { WM_KILLFOCUS, sent }, /* in MDI client */
2846 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2847 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2848 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2849 { WM_SETFOCUS, sent }, /* in MDI client */
2850
2851 { WM_DESTROY, sent },
2852
2853 { HCBT_SETFOCUS, hook }, /* set focus to MDI client */
2854 { WM_KILLFOCUS, sent },
2855 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
2856 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2857 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2858 { WM_SETFOCUS, sent }, /* in MDI client */
2859
2860 { HCBT_SETFOCUS, hook }, /* MDI client sets focus back to MDI child */
2861 { WM_KILLFOCUS, sent }, /* in MDI client */
2862 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2863 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
2864 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2865 { WM_SETFOCUS, sent }, /* in MDI client */
2866
2867 { WM_NCDESTROY, sent },
2868 { 0 }
2869 };
2870 /* CreateWindow for MDI child window, initially invisible */
2871 static const struct message WmCreateMDIchildInvisibleSeq[] = {
2872 { HCBT_CREATEWND, hook },
2873 { WM_NCCREATE, sent },
2874 { WM_NCCALCSIZE, sent|wparam, 0 },
2875 { WM_CREATE, sent },
2876 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2877 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2878 { WM_MOVE, sent },
2879 /* Win2k sends wparam set to
2880 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2881 * while Win9x doesn't bother to set child window id according to
2882 * CLIENTCREATESTRUCT.idFirstChild
2883 */
2884 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2885 { 0 }
2886 };
2887 /* DestroyWindow for MDI child window, initially invisible */
2888 static const struct message WmDestroyMDIchildInvisibleSeq[] = {
2889 { HCBT_DESTROYWND, hook },
2890 /* Win2k sends wparam set to
2891 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
2892 * while Win9x doesn't bother to set child window id according to
2893 * CLIENTCREATESTRUCT.idFirstChild
2894 */
2895 { 0x0090, sent|optional },
2896 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
2897 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
2898 { WM_DESTROY, sent },
2899 { WM_NCDESTROY, sent },
2900 /* FIXME: Wine destroys an icon/title window while Windows doesn't */
2901 { WM_PARENTNOTIFY, sent|wparam|optional, WM_DESTROY }, /* MDI client */
2902 { 0 }
2903 };
2904 /* CreateWindow for the 1st MDI child window, initially visible and maximized */
2905 static const struct message WmCreateMDIchildVisibleMaxSeq1[] = {
2906 { HCBT_CREATEWND, hook },
2907 { WM_NCCREATE, sent },
2908 { WM_NCCALCSIZE, sent|wparam, 0 },
2909 { WM_CREATE, sent },
2910 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2911 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2912 { WM_MOVE, sent },
2913 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2914 { WM_GETMINMAXINFO, sent },
2915 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2916 { WM_NCCALCSIZE, sent|wparam, 1 },
2917 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2918 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
2919 /* in MDI frame */
2920 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2921 { WM_NCCALCSIZE, sent|wparam, 1 },
2922 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2923 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2924 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2925 /* Win2k sends wparam set to
2926 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
2927 * while Win9x doesn't bother to set child window id according to
2928 * CLIENTCREATESTRUCT.idFirstChild
2929 */
2930 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
2931 { WM_SHOWWINDOW, sent|wparam, 1 },
2932 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2933 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
2934 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2935 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
2936 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
2937 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2938 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_FRAMECHANGED },
2939
2940 /* Win9x: message sequence terminates here. */
2941
2942 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
2943 { HCBT_SETFOCUS, hook|optional }, /* in MDI client */
2944 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
2945 { WM_IME_NOTIFY, sent|wparam|optional, 2 }, /* in MDI client */
2946 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2947 { WM_SETFOCUS, sent|optional }, /* in MDI client */
2948 { HCBT_SETFOCUS, hook|optional },
2949 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
2950 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
2951 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
2952 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2953 { WM_SETFOCUS, sent|defwinproc|optional },
2954 { WM_MDIACTIVATE, sent|defwinproc|optional },
2955 /* in MDI frame */
2956 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2957 { WM_NCCALCSIZE, sent|wparam, 1 },
2958 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2959 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2960 { 0 }
2961 };
2962 /* CreateWindow for the 2nd MDI child window, initially visible and maximized */
2963 static const struct message WmCreateMDIchildVisibleMaxSeq2[] = {
2964 /* restore the 1st MDI child */
2965 { WM_SETREDRAW, sent|wparam, 0 },
2966 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
2967 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
2968 { WM_NCCALCSIZE, sent|wparam, 1 },
2969 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
2970 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2971 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
2972 /* in MDI frame */
2973 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
2974 { WM_NCCALCSIZE, sent|wparam, 1 },
2975 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2976 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2977 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
2978 { WM_SETREDRAW, sent|wparam, 1 }, /* in the 1st MDI child */
2979 /* create the 2nd MDI child */
2980 { HCBT_CREATEWND, hook },
2981 { WM_NCCREATE, sent },
2982 { WM_NCCALCSIZE, sent|wparam, 0 },
2983 { WM_CREATE, sent },
2984 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
2985 { WM_SIZE, sent|wparam, SIZE_RESTORED },
2986 { WM_MOVE, sent },
2987 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
2988 { WM_GETMINMAXINFO, sent },
2989 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
2990 { WM_NCCALCSIZE, sent|wparam, 1 },
2991 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
2992 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
2993 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
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|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
2998 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
2999 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3000 /* Win2k sends wparam set to
3001 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3002 * while Win9x doesn't bother to set child window id according to
3003 * CLIENTCREATESTRUCT.idFirstChild
3004 */
3005 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3006 { WM_SHOWWINDOW, sent|wparam, 1 },
3007 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3008 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3009 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3010 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3011 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3012 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3013
3014 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
3015 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
3016
3017 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3018
3019 /* Win9x: message sequence terminates here. */
3020
3021 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3022 { HCBT_SETFOCUS, hook },
3023 { WM_KILLFOCUS, sent|defwinproc|optional }, /* in the 1st MDI child */
3024 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 }, /* in the 1st MDI child */
3025 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3026 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3027 { WM_SETFOCUS, sent }, /* in MDI client */
3028 { HCBT_SETFOCUS, hook },
3029 { WM_KILLFOCUS, sent }, /* in MDI client */
3030 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3031 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3032 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3033 { WM_SETFOCUS, sent|defwinproc },
3034
3035 { WM_MDIACTIVATE, sent|defwinproc },
3036 /* in MDI frame */
3037 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3038 { WM_NCCALCSIZE, sent|wparam, 1 },
3039 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3040 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3041 { 0 }
3042 };
3043 /* WM_MDICREATE MDI child window, initially visible and maximized */
3044 static const struct message WmCreateMDIchildVisibleMaxSeq3[] = {
3045 { WM_MDICREATE, sent },
3046 { HCBT_CREATEWND, hook },
3047 { WM_NCCREATE, sent },
3048 { WM_NCCALCSIZE, sent|wparam, 0 },
3049 { WM_CREATE, sent },
3050 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3051 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3052 { WM_MOVE, sent },
3053 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3054 { WM_GETMINMAXINFO, sent },
3055 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3056 { WM_NCCALCSIZE, sent|wparam, 1 },
3057 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3058 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3059
3060 /* in MDI frame */
3061 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3062 { WM_NCCALCSIZE, sent|wparam, 1 },
3063 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3064 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3065 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3066
3067 /* Win2k sends wparam set to
3068 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3069 * while Win9x doesn't bother to set child window id according to
3070 * CLIENTCREATESTRUCT.idFirstChild
3071 */
3072 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3073 { WM_SHOWWINDOW, sent|wparam, 1 },
3074 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3075
3076 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3077
3078 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3079 { WM_MDIREFRESHMENU, sent/*|wparam|lparam, 0, 0*/ },
3080 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
3081
3082 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3083 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3084
3085 /* Win9x: message sequence terminates here. */
3086
3087 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3088 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3089 { HCBT_SETFOCUS, hook }, /* in MDI client */
3090 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3091 { WM_IME_NOTIFY, sent|wparam|optional, 2 },
3092 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 },
3093 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3094 { HCBT_SETFOCUS, hook|optional },
3095 { WM_KILLFOCUS, sent }, /* in MDI client */
3096 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3097 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3098 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3099 { WM_SETFOCUS, sent|defwinproc },
3100
3101 { WM_MDIACTIVATE, sent|defwinproc },
3102
3103 /* in MDI child */
3104 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3105 { WM_NCCALCSIZE, sent|wparam, 1 },
3106 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3107 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
3108
3109 /* in MDI frame */
3110 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3111 { WM_NCCALCSIZE, sent|wparam, 1 },
3112 { 0x0093, sent|defwinproc|optional },
3113 { 0x0093, sent|defwinproc|optional },
3114 { 0x0093, sent|defwinproc|optional },
3115 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3116 { WM_MOVE, sent|defwinproc },
3117 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3118
3119 /* in MDI client */
3120 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3121 { WM_NCCALCSIZE, sent|wparam, 1 },
3122 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3123 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3124
3125 /* in MDI child */
3126 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3127 { WM_NCCALCSIZE, sent|wparam, 1 },
3128 { 0x0093, sent|optional },
3129 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3130 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3131
3132 { 0x0093, sent|optional },
3133 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3134 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3135 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP sends it to MDI frame */
3136 { 0x0093, sent|defwinproc|optional },
3137 { 0x0093, sent|defwinproc|optional },
3138 { 0x0093, sent|defwinproc|optional },
3139 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3140 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3141
3142 { 0 }
3143 };
3144 /* CreateWindow for the 1st MDI child window, initially invisible and maximized */
3145 static const struct message WmCreateMDIchildInvisibleMaxSeq4[] = {
3146 { HCBT_CREATEWND, hook },
3147 { WM_GETMINMAXINFO, sent },
3148 { WM_NCCREATE, sent },
3149 { WM_NCCALCSIZE, sent|wparam, 0 },
3150 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, 0, 0 },
3151 { WM_CREATE, sent },
3152 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
3153 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3154 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3155 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI frame */
3156 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOZORDER }, /* MDI frame */
3157 { WM_MOVE, sent },
3158 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3159 { WM_GETMINMAXINFO, sent },
3160 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_STATECHANGED },
3161 { WM_GETMINMAXINFO, sent|defwinproc },
3162 { WM_NCCALCSIZE, sent|wparam, 1 },
3163 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_STATECHANGED },
3164 { WM_MOVE, sent|defwinproc },
3165 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3166 /* in MDI frame */
3167 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3168 { WM_NCCALCSIZE, sent|wparam, 1 },
3169 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3170 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3171 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* MDI child */
3172 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3173 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3174 /* Win2k sends wparam set to
3175 * MAKEWPARAM(WM_CREATE, MDI_FIRST_CHILD_ID + nTotalCreated),
3176 * while Win9x doesn't bother to set child window id according to
3177 * CLIENTCREATESTRUCT.idFirstChild
3178 */
3179 { WM_PARENTNOTIFY, sent /*|wparam, WM_CREATE*/ }, /* in MDI client */
3180 { 0 }
3181 };
3182 /* WM_SYSCOMMAND/SC_CLOSE for the 2nd MDI child window, initially visible and maximized */
3183 static const struct message WmDestroyMDIchildVisibleMaxSeq2[] = {
3184 { WM_SYSCOMMAND, sent|wparam, SC_CLOSE },
3185 { HCBT_SYSCOMMAND, hook },
3186 { WM_CLOSE, sent|defwinproc },
3187 { WM_MDIDESTROY, sent }, /* in MDI client */
3188
3189 /* bring the 1st MDI child to top */
3190 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE }, /* in the 1st MDI child */
3191 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE }, /* in the 2nd MDI child */
3192
3193 { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3194
3195 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 }, /* in the 1st MDI child */
3196 { WM_NCACTIVATE, sent|wparam|defwinproc, 0 }, /* in the 1st MDI child */
3197 { WM_MDIACTIVATE, sent|defwinproc }, /* in the 1st MDI child */
3198
3199 /* maximize the 1st MDI child */
3200 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3201 { WM_GETMINMAXINFO, sent|defwinproc },
3202 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_STATECHANGED },
3203 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3204 { WM_CHILDACTIVATE, sent|defwinproc|wparam|lparam, 0, 0 },
3205 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3206 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3207
3208 /* restore the 2nd MDI child */
3209 { WM_SETREDRAW, sent|defwinproc|wparam, 0 },
3210 { HCBT_MINMAX, hook|lparam, 0, SW_NORMALNA },
3211 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3212 { WM_NCCALCSIZE, sent|defwinproc|wparam, 1 },
3213
3214 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3215
3216 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3217 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3218
3219 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3220
3221 { WM_SETREDRAW, sent|defwinproc|wparam, 1 },
3222 /* in MDI frame */
3223 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3224 { WM_NCCALCSIZE, sent|wparam, 1 },
3225 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3226 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3227 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3228
3229 /* bring the 1st MDI child to top */
3230 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3231 { WM_NCACTIVATE, sent|wparam|defwinproc, 1 },
3232 { HCBT_SETFOCUS, hook },
3233 { WM_KILLFOCUS, sent|defwinproc },
3234 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
3235 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3236 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3237 { WM_SETFOCUS, sent }, /* in MDI client */
3238 { HCBT_SETFOCUS, hook },
3239 { WM_KILLFOCUS, sent }, /* in MDI client */
3240 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3241 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3242 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3243 { WM_SETFOCUS, sent|defwinproc },
3244 { WM_MDIACTIVATE, sent|defwinproc },
3245 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3246
3247 /* apparently ShowWindow(SW_SHOW) on an MDI client */
3248 { WM_SHOWWINDOW, sent|wparam, 1 },
3249 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3250 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3251 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3252 { WM_MDIREFRESHMENU, sent },
3253
3254 { HCBT_DESTROYWND, hook },
3255 /* Win2k sends wparam set to
3256 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3257 * while Win9x doesn't bother to set child window id according to
3258 * CLIENTCREATESTRUCT.idFirstChild
3259 */
3260 { 0x0090, sent|defwinproc|optional },
3261 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3262 { WM_SHOWWINDOW, sent|defwinproc|wparam, 0 },
3263 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3264 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3265 { WM_ERASEBKGND, sent|parent|optional },
3266 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3267
3268 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3269 { WM_DESTROY, sent|defwinproc },
3270 { WM_NCDESTROY, sent|defwinproc },
3271 { 0 }
3272 };
3273 /* WM_MDIDESTROY for the single MDI child window, initially visible and maximized */
3274 static const struct message WmDestroyMDIchildVisibleMaxSeq1[] = {
3275 { WM_MDIDESTROY, sent }, /* in MDI client */
3276 { WM_SHOWWINDOW, sent|wparam, 0 },
3277 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3278 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3279 { WM_ERASEBKGND, sent|parent|optional },
3280 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3281
3282 { HCBT_SETFOCUS, hook },
3283 { WM_KILLFOCUS, sent },
3284 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3285 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3286 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3287 { WM_SETFOCUS, sent }, /* in MDI client */
3288 { HCBT_SETFOCUS, hook },
3289 { WM_KILLFOCUS, sent }, /* in MDI client */
3290 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3291 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3292 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3293 { WM_SETFOCUS, sent },
3294
3295 /* in MDI child */
3296 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3297 { WM_NCCALCSIZE, sent|wparam, 1 },
3298 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3299 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3300
3301 /* in MDI frame */
3302 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3303 { WM_NCCALCSIZE, sent|wparam, 1 },
3304 { 0x0093, sent|defwinproc|optional },
3305 { 0x0093, sent|defwinproc|optional },
3306 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3307 { WM_MOVE, sent|defwinproc },
3308 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3309
3310 /* in MDI client */
3311 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3312 { WM_NCCALCSIZE, sent|wparam, 1 },
3313 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3314 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3315
3316 /* in MDI child */
3317 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3318 { WM_NCCALCSIZE, sent|wparam, 1 },
3319 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3320 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3321
3322 /* in MDI child */
3323 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3324 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3325 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3326 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3327
3328 /* in MDI frame */
3329 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3330 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3331 { 0x0093, sent|defwinproc|optional },
3332 { 0x0093, sent|defwinproc|optional },
3333 { 0x0093, sent|defwinproc|optional },
3334 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3335 { WM_MOVE, sent|defwinproc },
3336 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3337
3338 /* in MDI client */
3339 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3340 { WM_NCCALCSIZE, sent|wparam, 1 },
3341 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3342 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3343
3344 /* in MDI child */
3345 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3346 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3347 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3348 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3349 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3350 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3351
3352 { 0x0093, sent|defwinproc|optional },
3353 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 }, /* XP sends it to MDI frame */
3354 { 0x0093, sent|defwinproc|optional },
3355 { 0x0093, sent|defwinproc|optional },
3356 { 0x0093, sent|defwinproc|optional },
3357 { 0x0093, sent|optional },
3358
3359 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3360 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3361 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3362 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3363 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3364
3365 /* in MDI frame */
3366 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3367 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3368 { 0x0093, sent|defwinproc|optional },
3369 { 0x0093, sent|defwinproc|optional },
3370 { 0x0093, sent|defwinproc|optional },
3371 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3372 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3373 { 0x0093, sent|optional },
3374
3375 { WM_NCACTIVATE, sent|wparam, 0 },
3376 { WM_MDIACTIVATE, sent },
3377
3378 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNORMAL },
3379 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_STATECHANGED },
3380 { WM_NCCALCSIZE, sent|wparam, 1 },
3381
3382 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3383
3384 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3385 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3386 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3387
3388 /* in MDI child */
3389 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3390 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3391 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3392 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3393
3394 /* in MDI frame */
3395 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3396 { WM_NCCALCSIZE, sent|wparam, 1 },
3397 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3398 { WM_MOVE, sent|defwinproc },
3399 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3400
3401 /* in MDI client */
3402 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3403 { WM_NCCALCSIZE, sent|wparam, 1 },
3404 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOCLIENTMOVE },
3405 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3406 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3407 { WM_NCCALCSIZE, sent|wparam|optional, 1 }, /* XP */
3408 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI client */
3409 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3410 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* XP sends a duplicate */
3411
3412 { HCBT_SETFOCUS, hook },
3413 { WM_KILLFOCUS, sent },
3414 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
3415 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3416 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3417 { WM_SETFOCUS, sent }, /* in MDI client */
3418
3419 { WM_MDIREFRESHMENU, sent }, /* in MDI client */
3420
3421 { HCBT_DESTROYWND, hook },
3422 /* Win2k sends wparam set to
3423 * MAKEWPARAM(WM_DESTROY, MDI_FIRST_CHILD_ID + nTotalCreated),
3424 * while Win9x doesn't bother to set child window id according to
3425 * CLIENTCREATESTRUCT.idFirstChild
3426 */
3427 { 0x0090, sent|optional },
3428 { WM_PARENTNOTIFY, sent /*|wparam, WM_DESTROY*/ }, /* in MDI client */
3429
3430 { WM_SHOWWINDOW, sent|wparam, 0 },
3431 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3432 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
3433 { WM_ERASEBKGND, sent|parent|optional },
3434 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3435
3436 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 },
3437 { WM_DESTROY, sent },
3438 { WM_NCDESTROY, sent },
3439 { 0 }
3440 };
3441 /* ShowWindow(SW_MAXIMIZE) for a not visible MDI child window */
3442 static const struct message WmMaximizeMDIchildInvisibleSeq[] = {
3443 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3444 { WM_GETMINMAXINFO, sent },
3445 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3446 { WM_NCCALCSIZE, sent|wparam, 1 },
3447 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3448 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3449
3450 { WM_WINDOWPOSCHANGING, sent|wparam|optional|defwinproc, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3451 { WM_NCACTIVATE, sent|wparam|optional|defwinproc, 1 },
3452 { HCBT_SETFOCUS, hook|optional },
3453 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3454 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3455 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3456 { HCBT_SETFOCUS, hook|optional },
3457 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3458 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3459 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3460 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3461 { WM_SETFOCUS, sent|optional|defwinproc },
3462 { WM_MDIACTIVATE, sent|optional|defwinproc },
3463 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3464 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3465 /* in MDI frame */
3466 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3467 { WM_NCCALCSIZE, sent|wparam, 1 },
3468 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3469 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3470 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3471 { 0 }
3472 };
3473 /* ShowWindow(SW_MAXIMIZE) for a not visible maximized MDI child window */
3474 static const struct message WmMaximizeMDIchildInvisibleSeq2[] = {
3475 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3476 { WM_GETMINMAXINFO, sent },
3477 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED },
3478 { WM_GETMINMAXINFO, sent|defwinproc },
3479 { WM_NCCALCSIZE, sent|wparam, 1 },
3480 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3481 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3482
3483 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3484 { WM_NCACTIVATE, sent|wparam|defwinproc|optional, 1 },
3485 { HCBT_SETFOCUS, hook|optional },
3486 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 }, /* in MDI client */
3487 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3488 { WM_SETFOCUS, sent|optional }, /* in MDI client */
3489 { HCBT_SETFOCUS, hook|optional },
3490 { WM_KILLFOCUS, sent|optional }, /* in MDI client */
3491 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, /* in MDI client */
3492 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
3493 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3494 { WM_SETFOCUS, sent|defwinproc|optional },
3495 { WM_MDIACTIVATE, sent|defwinproc|optional },
3496 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3497 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3498 { 0 }
3499 };
3500 /* WM_MDIMAXIMIZE for an MDI child window with invisible parent */
3501 static const struct message WmMaximizeMDIchildInvisibleParentSeq[] = {
3502 { WM_MDIMAXIMIZE, sent }, /* in MDI client */
3503 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3504 { WM_GETMINMAXINFO, sent },
3505 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3506 { WM_GETMINMAXINFO, sent|defwinproc },
3507 { WM_NCCALCSIZE, sent|wparam, 1 },
3508 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam|optional, 0, 0 }, /* XP doesn't send it */
3509 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3510 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOREDRAW|SWP_STATECHANGED },
3511 { WM_MOVE, sent|defwinproc },
3512 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3513
3514 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3515 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3516 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3517 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3518 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3519 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3520 /* in MDI frame */
3521 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3522 { WM_NCCALCSIZE, sent|wparam, 1 },
3523 { 0x0093, sent|defwinproc|optional },
3524 { 0x0094, sent|defwinproc|optional },
3525 { 0x0094, sent|defwinproc|optional },
3526 { 0x0094, sent|defwinproc|optional },
3527 { 0x0094, sent|defwinproc|optional },
3528 { 0x0093, sent|defwinproc|optional },
3529 { 0x0093, sent|defwinproc|optional },
3530 { 0x0091, sent|defwinproc|optional },
3531 { 0x0092, sent|defwinproc|optional },
3532 { 0x0092, sent|defwinproc|optional },
3533 { 0x0092, sent|defwinproc|optional },
3534 { 0x0092, sent|defwinproc|optional },
3535 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3536 { WM_MOVE, sent|defwinproc },
3537 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3538 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame win2000 */
3539 /* in MDI client */
3540 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOACTIVATE },
3541 { WM_NCCALCSIZE, sent|wparam, 1 },
3542 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3543 { WM_SIZE, sent|wparam, SIZE_RESTORED },
3544 /* in MDI child */
3545 { WM_WINDOWPOSCHANGING, sent|wparam|defwinproc, SWP_NOACTIVATE },
3546 { WM_GETMINMAXINFO, sent|defwinproc },
3547 { WM_NCCALCSIZE, sent|wparam|defwinproc, 1 },
3548 { WM_WINDOWPOSCHANGED, sent|wparam|defwinproc, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTMOVE },
3549 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3550 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child win2000 */
3551 { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, 1 },
3552 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3553 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3554 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI client XP */
3555 /* in MDI frame */
3556 { 0x0093, sent|optional },
3557 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
3558 { 0x0093, sent|defwinproc|optional },
3559 { 0x0093, sent|defwinproc|optional },
3560 { 0x0093, sent|defwinproc|optional },
3561 { 0x0091, sent|defwinproc|optional },
3562 { 0x0092, sent|defwinproc|optional },
3563 { 0x0092, sent|defwinproc|optional },
3564 { 0x0092, sent|defwinproc|optional },
3565 { 0x0092, sent|defwinproc|optional },
3566 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3567 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI frame XP */
3568 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* MDI child XP */
3569 { 0 }
3570 };
3571 /* ShowWindow(SW_MAXIMIZE) for a visible MDI child window */
3572 static const struct message WmMaximizeMDIchildVisibleSeq[] = {
3573 { HCBT_MINMAX, hook|lparam, 0, SW_MAXIMIZE },
3574 { WM_GETMINMAXINFO, sent },
3575 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3576 { WM_NCCALCSIZE, sent|wparam, 1 },
3577 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3578 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3579 { WM_SIZE, sent|defwinproc|wparam, SIZE_MAXIMIZED },
3580 /* in MDI frame */
3581 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3582 { WM_NCCALCSIZE, sent|wparam, 1 },
3583 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3584 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3585 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3586 { 0 }
3587 };
3588 /* ShowWindow(SW_RESTORE) for a visible maximized MDI child window */
3589 static const struct message WmRestoreMDIchildVisibleSeq[] = {
3590 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3591 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED },
3592 { WM_NCCALCSIZE, sent|wparam, 1 },
3593 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3594 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3595 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3596 /* in MDI frame */
3597 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3598 { WM_NCCALCSIZE, sent|wparam, 1 },
3599 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3600 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3601 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3602 { 0 }
3603 };
3604 /* ShowWindow(SW_RESTORE) for a visible minimized MDI child window */
3605 static const struct message WmRestoreMDIchildVisibleSeq_2[] = {
3606 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3607 { WM_QUERYOPEN, sent|wparam|lparam, 0, 0 },
3608 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3609 { WM_NCCALCSIZE, sent|wparam, 1 },
3610 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3611 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
3612 { WM_MOVE, sent|defwinproc },
3613 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3614 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3615 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3616 { HCBT_SETFOCUS, hook },
3617 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
3618 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
3619 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
3620 { WM_SETFOCUS, sent },
3621 { 0 }
3622 };
3623 /* ShowWindow(SW_MINIMIZE) for a visible restored MDI child window */
3624 static const struct message WmMinimizeMDIchildVisibleSeq[] = {
3625 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
3626 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3627 { WM_NCCALCSIZE, sent|wparam, 1 },
3628 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_STATECHANGED },
3629 { WM_MOVE, sent|defwinproc },
3630 { WM_SIZE, sent|defwinproc|wparam|lparam, SIZE_MINIMIZED, 0 },
3631 { WM_CHILDACTIVATE, sent|wparam|lparam|defwinproc, 0, 0 },
3632 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3633 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3634 /* FIXME: Wine creates an icon/title window while Windows doesn't */
3635 { WM_PARENTNOTIFY, sent|parent|wparam|optional, WM_CREATE }, /* MDI client */
3636 { 0 }
3637 };
3638 /* ShowWindow(SW_RESTORE) for a not visible MDI child window */
3639 static const struct message WmRestoreMDIchildInvisibleSeq[] = {
3640 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
3641 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_STATECHANGED },
3642 { WM_NCCALCSIZE, sent|wparam, 1 },
3643 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
3644 { WM_CHILDACTIVATE, sent|wparam|lparam, 0, 0 },
3645 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOCLIENTMOVE|SWP_STATECHANGED },
3646 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
3647 /* in MDI frame */
3648 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
3649 { WM_NCCALCSIZE, sent|wparam, 1 },
3650 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
3651 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI frame */
3652 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 }, /* MDI child */
3653 { 0 }
3654 };
3655
3656 static HWND mdi_client;
3657 static WNDPROC old_mdi_client_proc;
3658
3659 static LRESULT WINAPI mdi_client_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3660 {
3661 struct recvd_message msg;
3662
3663 /* do not log painting messages */
3664 if (message != WM_PAINT &&
3665 message != WM_NCPAINT &&
3666 message != WM_SYNCPAINT &&
3667 message != WM_ERASEBKGND &&
3668 message != WM_NCHITTEST &&
3669 message != WM_GETTEXT &&
3670 message != WM_MDIGETACTIVE &&
3671 !ignore_message( message ))
3672 {
3673 msg.hwnd = hwnd;
3674 msg.message = message;
3675 msg.flags = sent|wparam|lparam;
3676 msg.wParam = wParam;
3677 msg.lParam = lParam;
3678 msg.descr = "mdi client";
3679 add_message(&msg);
3680 }
3681
3682 return CallWindowProcA(old_mdi_client_proc, hwnd, message, wParam, lParam);
3683 }
3684
3685 static LRESULT WINAPI mdi_child_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3686 {
3687 static LONG defwndproc_counter = 0;
3688 LRESULT ret;
3689 struct recvd_message msg;
3690
3691 /* do not log painting messages */
3692 if (message != WM_PAINT &&
3693 message != WM_NCPAINT &&
3694 message != WM_SYNCPAINT &&
3695 message != WM_ERASEBKGND &&
3696 message != WM_NCHITTEST &&
3697 message != WM_GETTEXT &&
3698 !ignore_message( message ))
3699 {
3700 switch (message)
3701 {
3702 case WM_MDIACTIVATE:
3703 {
3704 HWND active, client = GetParent(hwnd);
3705
3706 active = (HWND)SendMessageA(client, WM_MDIGETACTIVE, 0, 0);
3707
3708 if (hwnd == (HWND)lParam) /* if we are being activated */
3709 ok (active == (HWND)lParam, "new active %p != active %p\n", (HWND)lParam, active);
3710 else
3711 ok (active == (HWND)wParam, "old active %p != active %p\n", (HWND)wParam, active);
3712 break;
3713 }
3714 }
3715
3716 msg.hwnd = hwnd;
3717 msg.message = message;
3718 msg.flags = sent|wparam|lparam;
3719 if (defwndproc_counter) msg.flags |= defwinproc;
3720 msg.wParam = wParam;
3721 msg.lParam = lParam;
3722 msg.descr = "mdi child";
3723 add_message(&msg);
3724 }
3725
3726 defwndproc_counter++;
3727 ret = DefMDIChildProcA(hwnd, message, wParam, lParam);
3728 defwndproc_counter--;
3729
3730 return ret;
3731 }
3732
3733 static LRESULT WINAPI mdi_frame_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3734 {
3735 static LONG defwndproc_counter = 0;
3736 LRESULT ret;
3737 struct recvd_message msg;
3738
3739 /* do not log painting messages */
3740 if (message != WM_PAINT &&
3741 message != WM_NCPAINT &&
3742 message != WM_SYNCPAINT &&
3743 message != WM_ERASEBKGND &&
3744 message != WM_NCHITTEST &&
3745 message != WM_GETTEXT &&
3746 !ignore_message( message ))
3747 {
3748 msg.hwnd = hwnd;
3749 msg.message = message;
3750 msg.flags = sent|wparam|lparam;
3751 if (defwndproc_counter) msg.flags |= defwinproc;
3752 msg.wParam = wParam;
3753 msg.lParam = lParam;
3754 msg.descr = "mdi frame";
3755 add_message(&msg);
3756 }
3757
3758 defwndproc_counter++;
3759 ret = DefFrameProcA(hwnd, mdi_client, message, wParam, lParam);
3760 defwndproc_counter--;
3761
3762 return ret;
3763 }
3764
3765 static BOOL mdi_RegisterWindowClasses(void)
3766 {
3767 WNDCLASSA cls;
3768
3769 cls.style = 0;
3770 cls.lpfnWndProc = mdi_frame_wnd_proc;
3771 cls.cbClsExtra = 0;
3772 cls.cbWndExtra = 0;
3773 cls.hInstance = GetModuleHandleA(0);
3774 cls.hIcon = 0;
3775 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
3776 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
3777 cls.lpszMenuName = NULL;
3778 cls.lpszClassName = "MDI_frame_class";
3779 if (!RegisterClassA(&cls)) return FALSE;
3780
3781 cls.lpfnWndProc = mdi_child_wnd_proc;
3782 cls.lpszClassName = "MDI_child_class";
3783 if (!RegisterClassA(&cls)) return FALSE;
3784
3785 if (!GetClassInfoA(0, "MDIClient", &cls)) assert(0);
3786 old_mdi_client_proc = cls.lpfnWndProc;
3787 cls.hInstance = GetModuleHandleA(0);
3788 cls.lpfnWndProc = mdi_client_hook_proc;
3789 cls.lpszClassName = "MDI_client_class";
3790 if (!RegisterClassA(&cls)) assert(0);
3791
3792 return TRUE;
3793 }
3794
3795 static void test_mdi_messages(void)
3796 {
3797 MDICREATESTRUCTA mdi_cs;
3798 CLIENTCREATESTRUCT client_cs;
3799 HWND mdi_frame, mdi_child, mdi_child2, active_child;
3800 BOOL zoomed;
3801 RECT rc;
3802 HMENU hMenu = CreateMenu();
3803 LONG val;
3804
3805 if (!mdi_RegisterWindowClasses()) assert(0);
3806
3807 flush_sequence();
3808
3809 trace("creating MDI frame window\n");
3810 mdi_frame = CreateWindowExA(0, "MDI_frame_class", "MDI frame window",
3811 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
3812 WS_MAXIMIZEBOX | WS_VISIBLE,
3813 100, 100, CW_USEDEFAULT, CW_USEDEFAULT,
3814 GetDesktopWindow(), hMenu,
3815 GetModuleHandleA(0), NULL);
3816 assert(mdi_frame);
3817 ok_sequence(WmCreateMDIframeSeq, "Create MDI frame window", FALSE);
3818
3819 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3820 ok(GetFocus() == mdi_frame, "wrong focus window %p\n", GetFocus());
3821
3822 trace("creating MDI client window\n");
3823 GetClientRect(mdi_frame, &rc);
3824 client_cs.hWindowMenu = 0;
3825 client_cs.idFirstChild = MDI_FIRST_CHILD_ID;
3826 mdi_client = CreateWindowExA(0, "MDI_client_class",
3827 NULL,
3828 WS_CHILD | WS_VISIBLE | MDIS_ALLCHILDSTYLES,
3829 rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
3830 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
3831 assert(mdi_client);
3832 SetWindowLongA(mdi_client, 0, 0xdeadbeef);
3833
3834 ok_sequence(WmCreateMDIclientSeq, "Create visible MDI client window", FALSE);
3835 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3836 ok(GetFocus() == mdi_frame, "input focus should be on MDI frame not on %p\n", GetFocus());
3837
3838 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3839 ok(!active_child, "wrong active MDI child %p\n", active_child);
3840 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3841
3842 SetFocus(0);
3843 flush_sequence();
3844
3845 trace("creating invisible MDI child window\n");
3846 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3847 WS_CHILD,
3848 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3849 mdi_client, 0, GetModuleHandleA(0), NULL);
3850 assert(mdi_child);
3851
3852 flush_sequence();
3853 ShowWindow(mdi_child, SW_SHOWNORMAL);
3854 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOWNORMAL) MDI child window", FALSE);
3855
3856 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3857 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3858
3859 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3860 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3861
3862 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3863 ok(!active_child, "wrong active MDI child %p\n", active_child);
3864 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3865
3866 ShowWindow(mdi_child, SW_HIDE);
3867 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE) MDI child window", FALSE);
3868 flush_sequence();
3869
3870 ShowWindow(mdi_child, SW_SHOW);
3871 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW) MDI child window", FALSE);
3872
3873 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3874 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3875
3876 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3877 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3878
3879 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3880 ok(!active_child, "wrong active MDI child %p\n", active_child);
3881 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3882
3883 DestroyWindow(mdi_child);
3884 flush_sequence();
3885
3886 trace("creating visible MDI child window\n");
3887 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3888 WS_CHILD | WS_VISIBLE,
3889 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3890 mdi_client, 0, GetModuleHandleA(0), NULL);
3891 assert(mdi_child);
3892 ok_sequence(WmCreateMDIchildVisibleSeq, "Create visible MDI child window", FALSE);
3893
3894 ok(GetWindowLongA(mdi_child, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3895 ok(IsWindowVisible(mdi_child), "MDI child should be visible\n");
3896
3897 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3898 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
3899
3900 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3901 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
3902 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3903 flush_sequence();
3904
3905 DestroyWindow(mdi_child);
3906 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
3907
3908 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3909 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3910
3911 /* Win2k: MDI client still returns a just destroyed child as active
3912 * Win9x: MDI client returns 0
3913 */
3914 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3915 ok(active_child == mdi_child || /* win2k */
3916 !active_child, /* win9x */
3917 "wrong active MDI child %p\n", active_child);
3918 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3919
3920 flush_sequence();
3921
3922 trace("creating invisible MDI child window\n");
3923 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
3924 WS_CHILD,
3925 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
3926 mdi_client, 0, GetModuleHandleA(0), NULL);
3927 assert(mdi_child2);
3928 ok_sequence(WmCreateMDIchildInvisibleSeq, "Create invisible MDI child window", FALSE);
3929
3930 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should not be visible\n");
3931 ok(!IsWindowVisible(mdi_child2), "MDI child should not be visible\n");
3932
3933 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3934 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3935
3936 /* Win2k: MDI client still returns a just destroyed child as active
3937 * Win9x: MDI client returns mdi_child2
3938 */
3939 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3940 ok(active_child == mdi_child || /* win2k */
3941 active_child == mdi_child2, /* win9x */
3942 "wrong active MDI child %p\n", active_child);
3943 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3944 flush_sequence();
3945
3946 ShowWindow(mdi_child2, SW_MAXIMIZE);
3947 ok_sequence(WmMaximizeMDIchildInvisibleSeq, "ShowWindow(SW_MAXIMIZE):invisible MDI child", FALSE);
3948
3949 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3950 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3951
3952 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3953 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3954 ok(zoomed, "wrong zoomed state %d\n", zoomed);
3955 flush_sequence();
3956
3957 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3958 ok(GetFocus() == mdi_child2 || /* win2k */
3959 GetFocus() == 0, /* win9x */
3960 "wrong focus window %p\n", GetFocus());
3961
3962 SetFocus(0);
3963 flush_sequence();
3964
3965 ShowWindow(mdi_child2, SW_HIDE);
3966 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3967
3968 ShowWindow(mdi_child2, SW_RESTORE);
3969 ok_sequence(WmRestoreMDIchildInvisibleSeq, "ShowWindow(SW_RESTORE):invisible MDI child", FALSE);
3970 flush_sequence();
3971
3972 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
3973 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
3974
3975 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
3976 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
3977 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
3978 flush_sequence();
3979
3980 SetFocus(0);
3981 flush_sequence();
3982
3983 ShowWindow(mdi_child2, SW_HIDE);
3984 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
3985
3986 ShowWindow(mdi_child2, SW_SHOW);
3987 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):MDI child", FALSE);
3988
3989 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3990 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3991
3992 ShowWindow(mdi_child2, SW_MAXIMIZE);
3993 ok_sequence(WmMaximizeMDIchildVisibleSeq, "ShowWindow(SW_MAXIMIZE):MDI child", FALSE);
3994
3995 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
3996 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
3997
3998 ShowWindow(mdi_child2, SW_RESTORE);
3999 ok_sequence(WmRestoreMDIchildVisibleSeq, "ShowWindow(SW_RESTORE):maximized MDI child", FALSE);
4000
4001 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4002 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4003
4004 ShowWindow(mdi_child2, SW_MINIMIZE);
4005 ok_sequence(WmMinimizeMDIchildVisibleSeq, "ShowWindow(SW_MINIMIZE):MDI child", TRUE);
4006
4007 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4008 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4009
4010 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4011 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4012 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4013 flush_sequence();
4014
4015 ShowWindow(mdi_child2, SW_RESTORE);
4016 ok_sequence(WmRestoreMDIchildVisibleSeq_2, "ShowWindow(SW_RESTORE):minimized MDI child", FALSE);
4017
4018 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4019 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4020
4021 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4022 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4023 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4024 flush_sequence();
4025
4026 SetFocus(0);
4027 flush_sequence();
4028
4029 ShowWindow(mdi_child2, SW_HIDE);
4030 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):MDI child", FALSE);
4031
4032 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4033 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4034
4035 DestroyWindow(mdi_child2);
4036 ok_sequence(WmDestroyMDIchildInvisibleSeq, "Destroy invisible MDI child window", FALSE);
4037
4038 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4039 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4040
4041 trace("Testing WM_CHILDACTIVATE\n");
4042
4043 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4044 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_DISABLED,
4045 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4046 mdi_client, 0, GetModuleHandleA(0), NULL);
4047
4048 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4049 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX,
4050 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4051 mdi_client, 0, GetModuleHandleA(0), NULL);
4052
4053 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4054 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4055 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4056
4057 flush_sequence();
4058 SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
4059 ok_sequence(WmChildActivateDisabledWindowSeq, "WM_CHILDACTIVATE sent to disabled window", FALSE);
4060
4061 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4062 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4063 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4064 flush_sequence();
4065
4066 EnableWindow(mdi_child, TRUE);
4067
4068 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4069 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4070 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4071
4072 flush_sequence();
4073 SendMessageW(mdi_child, WM_CHILDACTIVATE, 0, 0);
4074 ok_sequence(WmChildActivateWindowSeq, "WM_CHILDACTIVATE sent to enabled window", FALSE);
4075
4076 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4077 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4078 ok(!zoomed, "wrong zoomed state %d\n", zoomed);
4079 flush_sequence();
4080
4081 DestroyWindow(mdi_child);
4082 DestroyWindow(mdi_child2);
4083 flush_sequence();
4084
4085 /* test for maximized MDI children */
4086 trace("creating maximized visible MDI child window 1\n");
4087 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4088 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4089 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4090 mdi_client, 0, GetModuleHandleA(0), NULL);
4091 assert(mdi_child);
4092 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window", TRUE);
4093 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4094
4095 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4096 ok(GetFocus() == mdi_child || /* win2k */
4097 GetFocus() == 0, /* win9x */
4098 "wrong focus window %p\n", GetFocus());
4099
4100 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4101 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4102 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4103 flush_sequence();
4104
4105 trace("creating maximized visible MDI child window 2\n");
4106 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4107 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4108 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4109 mdi_client, 0, GetModuleHandleA(0), NULL);
4110 assert(mdi_child2);
4111 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4112 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4113 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4114
4115 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4116 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4117
4118 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4119 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4120 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4121 flush_sequence();
4122
4123 trace("destroying maximized visible MDI child window 2\n");
4124 DestroyWindow(mdi_child2);
4125 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4126
4127 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4128
4129 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4130 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4131
4132 /* Win2k: MDI client still returns a just destroyed child as active
4133 * Win9x: MDI client returns 0
4134 */
4135 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4136 ok(active_child == mdi_child2 || /* win2k */
4137 !active_child, /* win9x */
4138 "wrong active MDI child %p\n", active_child);
4139 flush_sequence();
4140
4141 ShowWindow(mdi_child, SW_MAXIMIZE);
4142 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4143 flush_sequence();
4144
4145 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4146 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4147
4148 trace("re-creating maximized visible MDI child window 2\n");
4149 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4150 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4151 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4152 mdi_client, 0, GetModuleHandleA(0), NULL);
4153 assert(mdi_child2);
4154 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child 2 window", TRUE);
4155 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized\n");
4156 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized\n");
4157
4158 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4159 ok(GetFocus() == mdi_child2, "wrong focus window %p\n", GetFocus());
4160
4161 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4162 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4163 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4164 flush_sequence();
4165
4166 SendMessageA(mdi_child2, WM_SYSCOMMAND, SC_CLOSE, 0);
4167 ok_sequence(WmDestroyMDIchildVisibleMaxSeq2, "WM_SYSCOMMAND/SC_CLOSE on a visible maximized MDI child window", TRUE);
4168 ok(!IsWindow(mdi_child2), "MDI child 2 should be destroyed\n");
4169
4170 ok(IsZoomed(mdi_child), "1st MDI child should be maximized\n");
4171 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4172 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4173
4174 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4175 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4176 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4177 flush_sequence();
4178
4179 DestroyWindow(mdi_child);
4180 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible MDI child window", TRUE);
4181
4182 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4183 ok(GetFocus() == 0, "wrong focus window %p\n", GetFocus());
4184
4185 /* Win2k: MDI client still returns a just destroyed child as active
4186 * Win9x: MDI client returns 0
4187 */
4188 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4189 ok(active_child == mdi_child || /* win2k */
4190 !active_child, /* win9x */
4191 "wrong active MDI child %p\n", active_child);
4192 flush_sequence();
4193
4194 trace("creating maximized invisible MDI child window\n");
4195 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4196 WS_CHILD | WS_MAXIMIZE | WS_CAPTION | WS_THICKFRAME,
4197 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4198 mdi_client, 0, GetModuleHandleA(0), NULL);
4199 assert(mdi_child2);
4200 ok_sequence(WmCreateMDIchildInvisibleMaxSeq4, "Create maximized invisible MDI child window", FALSE);
4201 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4202 ok(!(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE), "MDI child should be not visible\n");
4203 ok(!IsWindowVisible(mdi_child2), "MDI child should be not visible\n");
4204
4205 /* Win2k: MDI client still returns a just destroyed child as active
4206 * Win9x: MDI client returns 0
4207 */
4208 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4209 ok(active_child == mdi_child || /* win2k */
4210 !active_child || active_child == mdi_child2, /* win9x */
4211 "wrong active MDI child %p\n", active_child);
4212 flush_sequence();
4213
4214 trace("call ShowWindow(mdi_child, SW_MAXIMIZE)\n");
4215 ShowWindow(mdi_child2, SW_MAXIMIZE);
4216 ok_sequence(WmMaximizeMDIchildInvisibleSeq2, "ShowWindow(SW_MAXIMIZE):invisible maximized MDI child", FALSE);
4217 ok(IsZoomed(mdi_child2), "MDI child should be maximized\n");
4218 ok(GetWindowLongA(mdi_child2, GWL_STYLE) & WS_VISIBLE, "MDI child should be visible\n");
4219 ok(IsWindowVisible(mdi_child2), "MDI child should be visible\n");
4220
4221 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4222 ok(active_child == mdi_child2, "wrong active MDI child %p\n", active_child);
4223 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4224 flush_sequence();
4225
4226 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4227 flush_sequence();
4228
4229 /* end of test for maximized MDI children */
4230 SetFocus(0);
4231 flush_sequence();
4232 trace("creating maximized visible MDI child window 1(Switch test)\n");
4233 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4234 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4235 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4236 mdi_client, 0, GetModuleHandleA(0), NULL);
4237 assert(mdi_child);
4238 ok_sequence(WmCreateMDIchildVisibleMaxSeq1, "Create maximized visible 1st MDI child window(Switch test)", TRUE);
4239 ok(IsZoomed(mdi_child), "1st MDI child should be maximized(Switch test)\n");
4240
4241 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4242 ok(GetFocus() == mdi_child || /* win2k */
4243 GetFocus() == 0, /* win9x */
4244 "wrong focus window %p(Switch test)\n", GetFocus());
4245
4246 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4247 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4248 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4249 flush_sequence();
4250
4251 trace("creating maximized visible MDI child window 2(Switch test)\n");
4252 mdi_child2 = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4253 WS_CHILD | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE,
4254 0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
4255 mdi_client, 0, GetModuleHandleA(0), NULL);
4256 assert(mdi_child2);
4257 ok_sequence(WmCreateMDIchildVisibleMaxSeq2, "Create maximized visible 2nd MDI child window (Switch test)", TRUE);
4258
4259 ok(IsZoomed(mdi_child2), "2nd MDI child should be maximized(Switch test)\n");
4260 ok(!IsZoomed(mdi_child), "1st MDI child should NOT be maximized(Switch test)\n");
4261
4262 ok(GetActiveWindow() == mdi_frame, "wrong active window %p(Switch test)\n", GetActiveWindow());
4263 ok(GetFocus() == mdi_child2, "wrong focus window %p(Switch test)\n", GetFocus());
4264
4265 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4266 ok(active_child == mdi_child2, "wrong active MDI child %p(Switch test)\n", active_child);
4267 ok(zoomed, "wrong zoomed state %d(Switch test)\n", zoomed);
4268 flush_sequence();
4269
4270 trace("Switch child window.\n");
4271 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child, 0);
4272 ok_sequence(WmSwitchChild, "Child did not switch correctly", TRUE);
4273 trace("end of test for switch maximized MDI children\n");
4274 flush_sequence();
4275
4276 /* Prepare for switching test of not maximized MDI children */
4277 ShowWindow( mdi_child, SW_NORMAL );
4278 ok(!IsZoomed(mdi_child), "wrong zoomed state for %p(Switch test)\n", mdi_child);
4279 ok(!IsZoomed(mdi_child2), "wrong zoomed state for %p(Switch test)\n", mdi_child2);
4280 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0);
4281 ok(active_child == mdi_child, "wrong active MDI child %p(Switch test)\n", active_child);
4282 flush_sequence();
4283
4284 SendMessageA(mdi_client, WM_MDIACTIVATE, (WPARAM)mdi_child2, 0);
4285 ok_sequence(WmSwitchNotMaximizedChild, "Not maximized child did not switch correctly", FALSE);
4286 trace("end of test for switch not maximized MDI children\n");
4287 flush_sequence();
4288
4289 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4290 flush_sequence();
4291
4292 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child2, 0);
4293 flush_sequence();
4294
4295 SetFocus(0);
4296 flush_sequence();
4297 /* end of tests for switch maximized/not maximized MDI children */
4298
4299 mdi_cs.szClass = "MDI_child_Class";
4300 mdi_cs.szTitle = "MDI child";
4301 mdi_cs.hOwner = GetModuleHandleA(0);
4302 mdi_cs.x = 0;
4303 mdi_cs.y = 0;
4304 mdi_cs.cx = CW_USEDEFAULT;
4305 mdi_cs.cy = CW_USEDEFAULT;
4306 mdi_cs.style = WS_CHILD | WS_SYSMENU | WS_VISIBLE | WS_MAXIMIZEBOX | WS_MAXIMIZE;
4307 mdi_cs.lParam = 0;
4308 mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs);
4309 ok(mdi_child != 0, "MDI child creation failed\n");
4310 ok_sequence(WmCreateMDIchildVisibleMaxSeq3, "WM_MDICREATE for maximized visible MDI child window", TRUE);
4311
4312 ok(GetMenuItemID(hMenu, GetMenuItemCount(hMenu) - 1) == SC_CLOSE, "SC_CLOSE menu item not found\n");
4313
4314 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4315 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4316
4317 ok(IsZoomed(mdi_child), "MDI child should be maximized\n");
4318 ok(GetActiveWindow() == mdi_frame, "wrong active window %p\n", GetActiveWindow());
4319 ok(GetFocus() == mdi_child, "wrong focus window %p\n", GetFocus());
4320
4321 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4322 ok(active_child == mdi_child, "wrong active MDI child %p\n", active_child);
4323 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4324 flush_sequence();
4325
4326 SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0);
4327 ok_sequence(WmDestroyMDIchildVisibleMaxSeq1, "Destroy visible maximized MDI child window", TRUE);
4328
4329 ok(!IsWindow(mdi_child), "MDI child should be destroyed\n");
4330 active_child = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, (LPARAM)&zoomed);
4331 ok(!active_child, "wrong active MDI child %p\n", active_child);
4332
4333 SetFocus(0);
4334 flush_sequence();
4335
4336 val = GetWindowLongA(mdi_client, 0);
4337 ok(val == 0xdeadbeef || broken(val == 0) /* >= Win Vista */, "Expected 0xdeadbeef, got 0x%x\n", val);
4338 DestroyWindow(mdi_client);
4339 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4340
4341 /* test maximization of MDI child with invisible parent */
4342 client_cs.hWindowMenu = 0;
4343 mdi_client = CreateWindowA("MDI_client_class",
4344 NULL,
4345 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
4346 0, 0, 660, 430,
4347 mdi_frame, 0, GetModuleHandleA(0), &client_cs);
4348 ok_sequence(WmCreateMDIclientSeq, "Create MDI client window", FALSE);
4349
4350 ShowWindow(mdi_client, SW_HIDE);
4351 ok_sequence(WmHideMDIclientSeq, "Hide MDI client window", FALSE);
4352
4353 mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_class", "MDI child",
4354 WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
4355 0, 0, 650, 440,
4356 mdi_client, 0, GetModuleHandleA(0), NULL);
4357 ok_sequence(WmCreateMDIchildInvisibleParentSeq, "Create MDI child window with invisible parent", FALSE);
4358
4359 SendMessageA(mdi_client, WM_MDIMAXIMIZE, (WPARAM) mdi_child, 0);
4360 ok_sequence(WmMaximizeMDIchildInvisibleParentSeq, "Maximize MDI child window with invisible parent", TRUE);
4361 zoomed = IsZoomed(mdi_child);
4362 ok(zoomed, "wrong zoomed state %d\n", zoomed);
4363
4364 ShowWindow(mdi_client, SW_SHOW);
4365 ok_sequence(WmShowMDIclientSeq, "Show MDI client window", FALSE);
4366
4367 DestroyWindow(mdi_child);
4368 ok_sequence(WmDestroyMDIchildVisibleSeq, "Destroy visible maximized MDI child window", TRUE);
4369
4370 /* end of test for maximization of MDI child with invisible parent */
4371
4372 DestroyWindow(mdi_client);
4373 ok_sequence(WmDestroyMDIclientSeq, "Destroy MDI client window", FALSE);
4374
4375 DestroyWindow(mdi_frame);
4376 ok_sequence(WmDestroyMDIframeSeq, "Destroy MDI frame window", FALSE);
4377 }
4378 /************************* End of MDI test **********************************/
4379
4380 static void test_WM_SETREDRAW(HWND hwnd)
4381 {
4382 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
4383
4384 flush_events();
4385 flush_sequence();
4386
4387 SendMessageA(hwnd, WM_SETREDRAW, FALSE, 0);
4388 ok_sequence(WmSetRedrawFalseSeq, "SetRedraw:FALSE", FALSE);
4389
4390 ok(!(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should NOT be set\n");
4391 ok(!IsWindowVisible(hwnd), "IsWindowVisible() should return FALSE\n");
4392
4393 flush_sequence();
4394 SendMessageA(hwnd, WM_SETREDRAW, TRUE, 0);
4395 ok_sequence(WmSetRedrawTrueSeq, "SetRedraw:TRUE", FALSE);
4396
4397 ok(GetWindowLongA(hwnd, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
4398 ok(IsWindowVisible(hwnd), "IsWindowVisible() should return TRUE\n");
4399
4400 /* restore original WS_VISIBLE state */
4401 SetWindowLongA(hwnd, GWL_STYLE, style);
4402
4403 flush_events();
4404 flush_sequence();
4405 }
4406
4407 static INT_PTR CALLBACK TestModalDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4408 {
4409 struct recvd_message msg;
4410
4411 if (ignore_message( message )) return 0;
4412
4413 switch (message)
4414 {
4415 /* ignore */
4416 case WM_MOUSEMOVE:
4417 case WM_NCMOUSEMOVE:
4418 case WM_NCMOUSELEAVE:
4419 case WM_SETCURSOR:
4420 return 0;
4421 case WM_NCHITTEST:
4422 return HTCLIENT;
4423 }
4424
4425 msg.hwnd = hwnd;
4426 msg.message = message;
4427 msg.flags = sent|wparam|lparam;
4428 msg.wParam = wParam;
4429 msg.lParam = lParam;
4430 msg.descr = "dialog";
4431 add_message(&msg);
4432
4433 if (message == WM_INITDIALOG) SetTimer( hwnd, 1, 100, NULL );
4434 if (message == WM_TIMER) EndDialog( hwnd, 0 );
4435 return 0;
4436 }
4437
4438 static INT_PTR CALLBACK TestModalDlgProc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
4439 {
4440 struct recvd_message msg;
4441
4442 if (ignore_message( message )) return 0;
4443
4444 switch (message)
4445 {
4446 /* ignore */
4447 case WM_MOUSEMOVE:
4448 case WM_NCMOUSEMOVE:
4449 case WM_NCMOUSELEAVE:
4450 case WM_SETCURSOR:
4451 return 0;
4452 case WM_NCHITTEST:
4453 return HTCLIENT;
4454 }
4455
4456 msg.hwnd = hwnd;
4457 msg.message = message;
4458 msg.flags = sent|wparam|lparam;
4459 msg.wParam = wParam;
4460 msg.lParam = lParam;
4461 msg.descr = "dialog";
4462 add_message(&msg);
4463
4464 if (message == WM_INITDIALOG) EndDialog( hwnd, 0 );
4465 return 0;
4466 }
4467
4468 static void test_hv_scroll_1(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4469 {
4470 DWORD style, exstyle;
4471 INT xmin, xmax;
4472 BOOL ret;
4473
4474 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4475 style = GetWindowLongA(hwnd, GWL_STYLE);
4476 /* do not be confused by WS_DLGFRAME set */
4477 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4478
4479 if (clear) ok(style & clear, "style %08x should be set\n", clear);
4480 if (set) ok(!(style & set), "style %08x should not be set\n", set);
4481
4482 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4483 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4484 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4485 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollRange(SB_HORZ/SB_VERT) NC", FALSE);
4486 else
4487 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollRange(SB_HORZ/SB_VERT)", FALSE);
4488
4489 style = GetWindowLongA(hwnd, GWL_STYLE);
4490 if (set) ok(style & set, "style %08x should be set\n", set);
4491 if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4492
4493 /* a subsequent call should do nothing */
4494 ret = SetScrollRange(hwnd, ctl, min, max, FALSE);
4495 ok( ret, "SetScrollRange(%d) error %d\n", ctl, GetLastError());
4496 ok_sequence(WmEmptySeq, "SetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4497
4498 xmin = 0xdeadbeef;
4499 xmax = 0xdeadbeef;
4500 ret = GetScrollRange(hwnd, ctl, &xmin, &xmax);
4501 ok( ret, "GetScrollRange(%d) error %d\n", ctl, GetLastError());
4502 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4503 ok(xmin == min, "unexpected min scroll value %d\n", xmin);
4504 ok(xmax == max, "unexpected max scroll value %d\n", xmax);
4505 }
4506
4507 static void test_hv_scroll_2(HWND hwnd, INT ctl, DWORD clear, DWORD set, INT min, INT max)
4508 {
4509 DWORD style, exstyle;
4510 SCROLLINFO si;
4511 BOOL ret;
4512
4513 exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
4514 style = GetWindowLongA(hwnd, GWL_STYLE);
4515 /* do not be confused by WS_DLGFRAME set */
4516 if ((style & WS_CAPTION) == WS_CAPTION) style &= ~WS_CAPTION;
4517
4518 if (clear) ok(style & clear, "style %08x should be set\n", clear);
4519 if (set) ok(!(style & set), "style %08x should not be set\n", set);
4520
4521 si.cbSize = sizeof(si);
4522 si.fMask = SIF_RANGE;
4523 si.nMin = min;
4524 si.nMax = max;
4525 SetScrollInfo(hwnd, ctl, &si, TRUE);
4526 if ((style & (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME)) || (exstyle & WS_EX_DLGMODALFRAME))
4527 ok_sequence(WmSetScrollRangeHV_NC_Seq, "SetScrollInfo(SB_HORZ/SB_VERT) NC", FALSE);
4528 else
4529 ok_sequence(WmSetScrollRangeHVSeq, "SetScrollInfo(SB_HORZ/SB_VERT)", FALSE);
4530
4531 style = GetWindowLongA(hwnd, GWL_STYLE);
4532 if (set) ok(style & set, "style %08x should be set\n", set);
4533 if (clear) ok(!(style & clear), "style %08x should not be set\n", clear);
4534
4535 /* a subsequent call should do nothing */
4536 SetScrollInfo(hwnd, ctl, &si, TRUE);
4537 if (style & WS_HSCROLL)
4538 ok_sequence(WmSetScrollRangeHSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4539 else if (style & WS_VSCROLL)
4540 ok_sequence(WmSetScrollRangeVSeq_empty, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4541 else
4542 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4543
4544 si.fMask = SIF_PAGE;
4545 si.nPage = 5;
4546 SetScrollInfo(hwnd, ctl, &si, FALSE);
4547 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4548
4549 si.fMask = SIF_POS;
4550 si.nPos = max - 1;
4551 SetScrollInfo(hwnd, ctl, &si, FALSE);
4552 ok_sequence(WmEmptySeq, "SetScrollInfo(SB_HORZ/SB_VERT) empty sequence", FALSE);
4553
4554 si.fMask = SIF_RANGE;
4555 si.nMin = 0xdeadbeef;
4556 si.nMax = 0xdeadbeef;
4557 ret = GetScrollInfo(hwnd, ctl, &si);
4558 ok( ret, "GetScrollInfo error %d\n", GetLastError());
4559 ok_sequence(WmEmptySeq, "GetScrollRange(SB_HORZ/SB_VERT) empty sequence", FALSE);
4560 ok(si.nMin == min, "unexpected min scroll value %d\n", si.nMin);
4561 ok(si.nMax == max, "unexpected max scroll value %d\n", si.nMax);
4562 }
4563
4564 /* Win9x sends WM_USER+xxx while and NT versions send SBM_xxx messages */
4565 static void test_scroll_messages(HWND hwnd)
4566 {
4567 SCROLLINFO si;
4568 INT min, max;
4569 BOOL ret;
4570
4571 flush_events();
4572 flush_sequence();
4573
4574 min = 0xdeadbeef;
4575 max = 0xdeadbeef;
4576 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4577 ok( ret, "GetScrollRange error %d\n", GetLastError());
4578 if (sequence->message != WmGetScrollRangeSeq[0].message)
4579 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4580 /* values of min and max are undefined */
4581 flush_sequence();
4582
4583 ret = SetScrollRange(hwnd, SB_CTL, 10, 150, FALSE);
4584 ok( ret, "SetScrollRange error %d\n", GetLastError());
4585 if (sequence->message != WmSetScrollRangeSeq[0].message)
4586 trace("SetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4587 flush_sequence();
4588
4589 min = 0xdeadbeef;
4590 max = 0xdeadbeef;
4591 ret = GetScrollRange(hwnd, SB_CTL, &min, &max);
4592 ok( ret, "GetScrollRange error %d\n", GetLastError());
4593 if (sequence->message != WmGetScrollRangeSeq[0].message)
4594 trace("GetScrollRange(SB_CTL) generated unknown message %04x\n", sequence->message);
4595 /* values of min and max are undefined */
4596 flush_sequence();
4597
4598 si.cbSize = sizeof(si);
4599 si.fMask = SIF_RANGE;
4600 si.nMin = 20;
4601 si.nMax = 160;
4602 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4603 if (sequence->message != WmSetScrollRangeSeq[0].message)
4604 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4605 flush_sequence();
4606
4607 si.fMask = SIF_PAGE;
4608 si.nPage = 10;
4609 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4610 if (sequence->message != WmSetScrollRangeSeq[0].message)
4611 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4612 flush_sequence();
4613
4614 si.fMask = SIF_POS;
4615 si.nPos = 20;
4616 SetScrollInfo(hwnd, SB_CTL, &si, FALSE);
4617 if (sequence->message != WmSetScrollRangeSeq[0].message)
4618 trace("SetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4619 flush_sequence();
4620
4621 si.fMask = SIF_RANGE;
4622 si.nMin = 0xdeadbeef;
4623 si.nMax = 0xdeadbeef;
4624 ret = GetScrollInfo(hwnd, SB_CTL, &si);
4625 ok( ret, "GetScrollInfo error %d\n", GetLastError());
4626 if (sequence->message != WmGetScrollInfoSeq[0].message)
4627 trace("GetScrollInfo(SB_CTL) generated unknown message %04x\n", sequence->message);
4628 /* values of min and max are undefined */
4629 flush_sequence();
4630
4631 /* set WS_HSCROLL */
4632 test_hv_scroll_1(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4633 /* clear WS_HSCROLL */
4634 test_hv_scroll_1(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4635
4636 /* set WS_HSCROLL */
4637 test_hv_scroll_2(hwnd, SB_HORZ, 0, WS_HSCROLL, 10, 150);
4638 /* clear WS_HSCROLL */
4639 test_hv_scroll_2(hwnd, SB_HORZ, WS_HSCROLL, 0, 0, 0);
4640
4641 /* set WS_VSCROLL */
4642 test_hv_scroll_1(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4643 /* clear WS_VSCROLL */
4644 test_hv_scroll_1(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4645
4646 /* set WS_VSCROLL */
4647 test_hv_scroll_2(hwnd, SB_VERT, 0, WS_VSCROLL, 10, 150);
4648 /* clear WS_VSCROLL */
4649 test_hv_scroll_2(hwnd, SB_VERT, WS_VSCROLL, 0, 0, 0);
4650 }
4651
4652 static void test_showwindow(void)
4653 {
4654 HWND hwnd, hchild;
4655 RECT rc;
4656
4657 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
4658 100, 100, 200, 200, 0, 0, 0, NULL);
4659 ok (hwnd != 0, "Failed to create overlapped window\n");
4660 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
4661 0, 0, 10, 10, hwnd, 0, 0, NULL);
4662 ok (hchild != 0, "Failed to create child\n");
4663 flush_sequence();
4664
4665 /* ShowWindow( SW_SHOWNA) for invisible top level window */
4666 trace("calling ShowWindow( SW_SHOWNA) for invisible top level window\n");
4667 ok( ShowWindow(hwnd, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4668 ok_sequence(WmSHOWNATopInvisible, "ShowWindow(SW_SHOWNA) on invisible top level window", FALSE);
4669
4670 /* ShowWindow( SW_SHOWNA) for now visible top level window */
4671 trace("calling ShowWindow( SW_SHOWNA) for now visible top level window\n");
4672 ok( ShowWindow(hwnd, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4673 ok_sequence(WmSHOWNATopVisible, "ShowWindow(SW_SHOWNA) on visible top level window", FALSE);
4674 /* back to invisible */
4675 ShowWindow(hchild, SW_HIDE);
4676 ShowWindow(hwnd, SW_HIDE);
4677 flush_sequence();
4678 /* ShowWindow(SW_SHOWNA) with child and parent invisible */
4679 trace("calling ShowWindow( SW_SHOWNA) for invisible child with invisible parent\n");
4680 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4681 ok_sequence(WmSHOWNAChildInvisParInvis, "ShowWindow(SW_SHOWNA) invisible child and parent", FALSE);
4682 /* ShowWindow(SW_SHOWNA) with child visible and parent invisible */
4683 ok( ShowWindow(hchild, SW_SHOW) != FALSE, "ShowWindow: window was invisible\n" );
4684 flush_sequence();
4685 trace("calling ShowWindow( SW_SHOWNA) for the visible child and invisible parent\n");
4686 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4687 ok_sequence(WmSHOWNAChildVisParInvis, "ShowWindow(SW_SHOWNA) visible child and invisible parent", FALSE);
4688 /* ShowWindow(SW_SHOWNA) with child visible and parent visible */
4689 ShowWindow( hwnd, SW_SHOW);
4690 flush_sequence();
4691 trace("calling ShowWindow( SW_SHOWNA) for the visible child and parent\n");
4692 ok( ShowWindow(hchild, SW_SHOWNA) != FALSE, "ShowWindow: window was invisible\n" );
4693 ok_sequence(WmSHOWNAChildVisParVis, "ShowWindow(SW_SHOWNA) for the visible child and parent", FALSE);
4694
4695 /* ShowWindow(SW_SHOWNA) with child invisible and parent visible */
4696 ShowWindow( hchild, SW_HIDE);
4697 flush_sequence();
4698 trace("calling ShowWindow( SW_SHOWNA) for the invisible child and visible parent\n");
4699 ok( ShowWindow(hchild, SW_SHOWNA) == FALSE, "ShowWindow: window was visible\n" );
4700 ok_sequence(WmSHOWNAChildInvisParVis, "ShowWindow(SW_SHOWNA) for the invisible child and visible parent", FALSE);
4701
4702 SetCapture(hchild);
4703 ok(GetCapture() == hchild, "wrong capture window %p\n", GetCapture());
4704 DestroyWindow(hchild);
4705 ok(!GetCapture(), "wrong capture window %p\n", GetCapture());
4706
4707 DestroyWindow(hwnd);
4708 flush_sequence();
4709
4710 /* Popup windows */
4711 /* Test 1:
4712 * 1. Create invisible maximized popup window.
4713 * 2. Move and resize it.
4714 * 3. Show it maximized.
4715 */
4716 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4717 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4718 100, 100, 200, 200, 0, 0, 0, NULL);
4719 ok (hwnd != 0, "Failed to create popup window\n");
4720 ok(IsZoomed(hwnd), "window should be maximized\n");
4721 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4722
4723 GetWindowRect(hwnd, &rc);
4724 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4725 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4726 "Invalid maximized size before ShowWindow %s\n", wine_dbgstr_rect( &rc ));
4727 /* Reset window's size & position */
4728 SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4729 ok(IsZoomed(hwnd), "window should be maximized\n");
4730 flush_sequence();
4731
4732 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4733 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4734 ok(IsZoomed(hwnd), "window should be maximized\n");
4735 ok_sequence(WmShowMaxPopupResizedSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup", FALSE);
4736
4737 GetWindowRect(hwnd, &rc);
4738 ok( rc.right-rc.left == GetSystemMetrics(SM_CXSCREEN) &&
4739 rc.bottom-rc.top == GetSystemMetrics(SM_CYSCREEN),
4740 "Invalid maximized size after ShowWindow %s\n", wine_dbgstr_rect( &rc ));
4741 DestroyWindow(hwnd);
4742 flush_sequence();
4743
4744 /* Test again, this time the NC_PAINT message */
4745 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4746 100, 100, 200, 200, 0, 0, 0, NULL);
4747 ok (hwnd != 0, "Failed to create popup window\n");
4748 SetWindowPos(hwnd, 0, 10, 10, 200, 200, SWP_NOZORDER | SWP_NOACTIVATE);
4749 flush_sequence();
4750 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4751 ok_sequence(WmShowMaxPopupResizedSeq_todo,
4752 "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized and resized popup TODO", TRUE);
4753 DestroyWindow(hwnd);
4754 flush_sequence();
4755
4756 /* Test 2:
4757 * 1. Create invisible maximized popup window.
4758 * 2. Show it maximized.
4759 */
4760 trace("calling CreateWindowExA( WS_MAXIMIZE ) for invisible maximized popup window\n");
4761 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE,
4762 100, 100, 200, 200, 0, 0, 0, NULL);
4763 ok (hwnd != 0, "Failed to create popup window\n");
4764 ok(IsZoomed(hwnd), "window should be maximized\n");
4765 ok_sequence(WmCreateInvisibleMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4766
4767 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for invisible maximized popup window\n");
4768 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4769 ok(IsZoomed(hwnd), "window should be maximized\n");
4770 ok_sequence(WmShowMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):invisible maximized popup", FALSE);
4771 DestroyWindow(hwnd);
4772 flush_sequence();
4773
4774 /* Test 3:
4775 * 1. Create visible maximized popup window.
4776 */
4777 trace("calling CreateWindowExA( WS_MAXIMIZE ) for maximized popup window\n");
4778 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
4779 100, 100, 200, 200, 0, 0, 0, NULL);
4780 ok (hwnd != 0, "Failed to create popup window\n");
4781 ok(IsZoomed(hwnd), "window should be maximized\n");
4782 ok_sequence(WmCreateMaxPopupSeq, "CreateWindow(WS_MAXIMIZED):popup", FALSE);
4783 DestroyWindow(hwnd);
4784 flush_sequence();
4785
4786 /* Test 4:
4787 * 1. Create visible popup window.
4788 * 2. Maximize it.
4789 */
4790 trace("calling CreateWindowExA( WS_VISIBLE ) for popup window\n");
4791 hwnd = CreateWindowExA(0, "TestWindowClass", "Test popup", WS_POPUP | WS_VISIBLE,
4792 100, 100, 200, 200, 0, 0, 0, NULL);
4793 ok (hwnd != 0, "Failed to create popup window\n");
4794 ok(!IsZoomed(hwnd), "window should NOT be maximized\n");
4795 ok_sequence(WmCreatePopupSeq, "CreateWindow(WS_VISIBLE):popup", FALSE);
4796
4797 trace("calling ShowWindow( SW_SHOWMAXIMIZE ) for visible popup window\n");
4798 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
4799 ok(IsZoomed(hwnd), "window should be maximized\n");
4800 ok_sequence(WmShowVisMaxPopupSeq, "ShowWindow(SW_SHOWMAXIMIZED):popup", FALSE);
4801 DestroyWindow(hwnd);
4802 flush_sequence();
4803 }
4804
4805 static void test_sys_menu(void)
4806 {
4807 HWND hwnd;
4808 HMENU hmenu;
4809 UINT state;
4810
4811 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4812 100, 100, 200, 200, 0, 0, 0, NULL);
4813 ok (hwnd != 0, "Failed to create overlapped window\n");
4814
4815 flush_sequence();
4816
4817 /* test existing window without CS_NOCLOSE style */
4818 hmenu = GetSystemMenu(hwnd, FALSE);
4819 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4820
4821 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4822 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4823 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4824
4825 EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
4826 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4827
4828 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4829 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4830 ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
4831
4832 EnableMenuItem(hmenu, SC_CLOSE, 0);
4833 ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
4834
4835 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4836 ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4837 ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
4838
4839 /* test whether removing WS_SYSMENU destroys a system menu */
4840 SetWindowLongW(hwnd, GWL_STYLE, WS_POPUP);
4841 SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
4842 flush_sequence();
4843 hmenu = GetSystemMenu(hwnd, FALSE);
4844 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4845
4846 DestroyWindow(hwnd);
4847
4848 /* test new window with CS_NOCLOSE style */
4849 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
4850 100, 100, 200, 200, 0, 0, 0, NULL);
4851 ok (hwnd != 0, "Failed to create overlapped window\n");
4852
4853 hmenu = GetSystemMenu(hwnd, FALSE);
4854 ok(hmenu != 0, "GetSystemMenu error %d\n", GetLastError());
4855
4856 state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
4857 ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
4858
4859 DestroyWindow(hwnd);
4860
4861 /* test new window without WS_SYSMENU style */
4862 hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
4863 100, 100, 200, 200, 0, 0, 0, NULL);
4864 ok(hwnd != 0, "Failed to create overlapped window\n");
4865
4866 hmenu = GetSystemMenu(hwnd, FALSE);
4867 ok(!hmenu, "GetSystemMenu error %d\n", GetLastError());
4868
4869 DestroyWindow(hwnd);
4870 }
4871
4872 /* For shown WS_OVERLAPPEDWINDOW */
4873 static const struct message WmSetIcon_1[] = {
4874 { WM_SETICON, sent },
4875 { 0x00AE, sent|defwinproc|optional }, /* XP */
4876 { WM_GETTEXT, sent|defwinproc|optional },
4877 { WM_GETTEXT, sent|defwinproc|optional }, /* XP sends a duplicate */
4878 { 0 }
4879 };
4880
4881 /* For WS_POPUP and hidden WS_OVERLAPPEDWINDOW */
4882 static const struct message WmSetIcon_2[] = {
4883 { WM_SETICON, sent },
4884 { 0 }
4885 };
4886
4887 /* Sending undocumented 0x3B message with wparam = 0x8000000b */
4888 static const struct message WmInitEndSession[] = {
4889 { 0x003B, sent },
4890 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4891 { 0 }
4892 };
4893
4894 /* Sending undocumented 0x3B message with wparam = 0x0000000b */
4895 static const struct message WmInitEndSession_2[] = {
4896 { 0x003B, sent },
4897 { WM_QUERYENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4898 { 0 }
4899 };
4900
4901 /* Sending undocumented 0x3B message with wparam = 0x80000008 */
4902 static const struct message WmInitEndSession_3[] = {
4903 { 0x003B, sent },
4904 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, ENDSESSION_LOGOFF },
4905 { 0 }
4906 };
4907
4908 /* Sending undocumented 0x3B message with wparam = 0x00000008 */
4909 static const struct message WmInitEndSession_4[] = {
4910 { 0x003B, sent },
4911 { WM_ENDSESSION, sent|defwinproc|wparam|lparam, 0, 0 },
4912 { 0 }
4913 };
4914
4915 /* Sending undocumented 0x3B message with wparam = 0x80000001 */
4916 static const struct message WmInitEndSession_5[] = {
4917 { 0x003B, sent },
4918 { WM_ENDSESSION, sent|defwinproc/*|wparam*/|lparam, 1, ENDSESSION_LOGOFF },
4919 { 0 }
4920 };
4921
4922 static const struct message WmOptionalPaint[] = {
4923 { WM_PAINT, sent|optional },
4924 { WM_NCPAINT, sent|beginpaint|optional },
4925 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
4926 { WM_ERASEBKGND, sent|beginpaint|optional },
4927 { 0 }
4928 };
4929
4930 static const struct message WmZOrder[] = {
4931 { WM_WINDOWPOSCHANGING, sent|wparam, 0, 0 },
4932 { WM_GETMINMAXINFO, sent|defwinproc|wparam, 0, 0 },
4933 { HCBT_ACTIVATE, hook },
4934 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
4935 { WM_WINDOWPOSCHANGING, sent|wparam, 3, 0 },
4936 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOREDRAW|SWP_NOMOVE|SWP_NOSIZE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0 },
4937 { WM_GETTEXT, sent|optional },
4938 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
4939 { WM_ACTIVATEAPP, sent|wparam, 1, 0 },
4940 { WM_NCACTIVATE, sent|lparam, 1, 0 },
4941 { WM_GETTEXT, sent|defwinproc|optional },
4942 { WM_GETTEXT, sent|defwinproc|optional },
4943 { WM_ACTIVATE, sent|wparam|lparam, 1, 0 },
4944 { HCBT_SETFOCUS, hook },
4945 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
4946 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
4947 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
4948 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
4949 { WM_GETTEXT, sent|optional },
4950 { WM_NCCALCSIZE, sent|optional },
4951 { 0 }
4952 };
4953
4954 static void CALLBACK apc_test_proc(ULONG_PTR param)
4955 {
4956 /* nothing */
4957 }
4958
4959 static void test_MsgWaitForMultipleObjects(HWND hwnd)
4960 {
4961 DWORD ret;
4962 MSG msg;
4963
4964 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4965 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4966
4967 PostMessageA(hwnd, WM_USER, 0, 0);
4968
4969 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4970 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4971
4972 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4973 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4974
4975 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4976 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4977
4978 PostMessageA(hwnd, WM_USER, 0, 0);
4979
4980 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4981 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4982
4983 ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
4984 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4985
4986 /* shows QS_POSTMESSAGE flag is cleared in the PeekMessage call */
4987 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4988 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %x\n", ret);
4989
4990 PostMessageA(hwnd, WM_USER, 0, 0);
4991
4992 /* new incoming message causes it to become signaled again */
4993 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
4994 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
4995
4996 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4997 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
4998 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
4999 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5000
5001 /* MWMO_INPUTAVAILABLE should succeed even if the message was already seen */
5002 PostMessageA( hwnd, WM_USER, 0, 0 );
5003 ok(PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ), "PeekMessage should succeed\n");
5004 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5005
5006 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_INPUTAVAILABLE );
5007 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5008
5009 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5010 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5011
5012 /* without MWMO_ALERTABLE the result is never WAIT_IO_COMPLETION */
5013 ret = QueueUserAPC( apc_test_proc, GetCurrentThread(), 0 );
5014 ok(ret, "QueueUserAPC failed %u\n", GetLastError());
5015
5016 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, 0 );
5017 ok(ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5018
5019 /* but even with MWMO_ALERTABLE window events are preferred */
5020 PostMessageA( hwnd, WM_USER, 0, 0 );
5021
5022 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
5023 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5024
5025 ok(PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n");
5026 ok(msg.message == WM_USER, "got %04x instead of WM_USER\n", msg.message);
5027
5028 /* the APC call is still queued */
5029 ret = MsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_POSTMESSAGE, MWMO_ALERTABLE );
5030 ok(ret == WAIT_IO_COMPLETION, "MsgWaitForMultipleObjectsEx returned %x\n", ret);
5031 }
5032
5033 static void test_WM_DEVICECHANGE(HWND hwnd)
5034 {
5035 DWORD ret;
5036 MSG msg;
5037 int i;
5038 static const WPARAM wparams[] = {0,
5039 DBT_DEVNODES_CHANGED,
5040 DBT_QUERYCHANGECONFIG,
5041 DBT_CONFIGCHANGED,
5042 DBT_CONFIGCHANGECANCELED,
5043 DBT_NO_DISK_SPACE,
5044 DBT_LOW_DISK_SPACE,
5045 DBT_CONFIGMGPRIVATE, /* 0x7fff */
5046 DBT_DEVICEARRIVAL, /* 0x8000 */
5047 DBT_DEVICEQUERYREMOVE,
5048 DBT_DEVICEQUERYREMOVEFAILED,
5049 DBT_DEVICEREMOVEPENDING,
5050 DBT_DEVICEREMOVECOMPLETE,
5051 DBT_DEVICETYPESPECIFIC,
5052 DBT_CUSTOMEVENT};
5053
5054 for (i = 0; i < sizeof(wparams)/sizeof(wparams[0]); i++)
5055 {
5056 SetLastError(0xdeadbeef);
5057 ret = PostMessageA(hwnd, WM_DEVICECHANGE, wparams[i], 0);
5058 if (wparams[i] & 0x8000)
5059 {
5060 ok(ret == FALSE, "PostMessage should returned %d\n", ret);
5061 ok(GetLastError() == ERROR_MESSAGE_SYNC_ONLY, "PostMessage error %08x\n", GetLastError());
5062 }
5063 else
5064 {
5065 ret = MsgWaitForMultipleObjects(0, NULL, FALSE, 0, QS_POSTMESSAGE);
5066 ok(ret == WAIT_OBJECT_0, "MsgWaitForMultipleObjects returned %x\n", ret);
5067 memset(&msg, 0, sizeof(msg));
5068 ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should succeed\n");
5069 ok(msg.message == WM_DEVICECHANGE, "got %04x instead of WM_DEVICECHANGE\n", msg.message);
5070 }
5071 }
5072 }
5073
5074 static DWORD CALLBACK show_window_thread(LPVOID arg)
5075 {
5076 HWND hwnd = arg;
5077
5078 /* function will not return if ShowWindow(SW_HIDE) calls SendMessage() */
5079 ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5080
5081 return 0;
5082 }
5083
5084 /* Helper function to easier test SetWindowPos messages */
5085 #define test_msg_setpos( expected_list, flags, todo ) \
5086 test_msg_setpos_( (expected_list), (flags), (todo), __FILE__, __LINE__)
5087 static void test_msg_setpos_(const struct message *expected_list, UINT flags, BOOL todo, const char *file, int line)
5088 {
5089 HWND hwnd;
5090
5091 flush_events();
5092 flush_sequence();
5093 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5094 10, 10, 100, 100, NULL, 0, 0, NULL );
5095 ok (hwnd != 0, "Failed to create popup window\n");
5096 SetWindowPos(hwnd, NULL, 0, 0, 100, 100, flags);
5097 ok_sequence_(expected_list, "SetWindowPos:show_popup_first_show_window", todo, file, line);
5098 DestroyWindow(hwnd);
5099 }
5100
5101 /* test if we receive the right sequence of messages */
5102 static void test_messages(void)
5103 {
5104 DWORD tid;
5105 HANDLE hthread;
5106 HWND hwnd, hparent, hchild;
5107 HWND hchild2, hbutton;
5108 HMENU hmenu;
5109 MSG msg;
5110 LRESULT res;
5111 POINT pos;
5112 BOOL ret;
5113
5114 flush_sequence();
5115
5116 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5117 100, 100, 200, 200, 0, 0, 0, NULL);
5118 ok (hwnd != 0, "Failed to create overlapped window\n");
5119 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5120
5121 /* test ShowWindow(SW_HIDE) on a newly created invisible window */
5122 ok( ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow: window was visible\n" );
5123 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped, invisible", FALSE);
5124
5125 /* test WM_SETREDRAW on a not visible top level window */
5126 test_WM_SETREDRAW(hwnd);
5127
5128 SetWindowPos(hwnd, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5129 flush_events();
5130 ok_sequence(WmSWP_ShowOverlappedSeq, "SetWindowPos:SWP_SHOWWINDOW:overlapped", FALSE);
5131 ok(IsWindowVisible(hwnd), "window should be visible at this point\n");
5132
5133 ok(GetActiveWindow() == hwnd, "window should be active\n");
5134 ok(GetFocus() == hwnd, "window should have input focus\n");
5135 ShowWindow(hwnd, SW_HIDE);
5136 flush_events();
5137 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5138
5139 /* test ShowWindow(SW_HIDE) on a hidden window - single threaded */
5140 ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n");
5141 flush_events();
5142 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5143
5144 /* test ShowWindow(SW_HIDE) on a hidden window - multi-threaded */
5145 hthread = CreateThread(NULL, 0, show_window_thread, hwnd, 0, &tid);
5146 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
5147 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
5148 CloseHandle(hthread);
5149 flush_events();
5150 ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5151
5152 ShowWindow(hwnd, SW_SHOW);
5153 flush_events();
5154 ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE);
5155
5156 ShowWindow(hwnd, SW_HIDE);
5157 flush_events();
5158 ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
5159
5160 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5161 flush_events();
5162 ok_sequence(WmShowMaxOverlappedSeq, "ShowWindow(SW_SHOWMAXIMIZED):overlapped", TRUE);
5163 flush_sequence();
5164
5165 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZE)
5166 {
5167 ShowWindow(hwnd, SW_RESTORE);
5168 flush_events();
5169 ok_sequence(WmShowRestoreMaxOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
5170 flush_sequence();
5171 }
5172
5173 ShowWindow(hwnd, SW_MINIMIZE);
5174 flush_events();
5175 ok_sequence(WmShowMinOverlappedSeq, "ShowWindow(SW_SHOWMINIMIZED):overlapped", TRUE);
5176 flush_sequence();
5177
5178 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MINIMIZE)
5179 {
5180 ShowWindow(hwnd, SW_RESTORE);
5181 flush_events();
5182 ok_sequence(WmShowRestoreMinOverlappedSeq, "ShowWindow(SW_RESTORE):overlapped", TRUE);
5183 flush_sequence();
5184 }
5185
5186 ShowWindow(hwnd, SW_SHOW);
5187 flush_events();
5188 ok_sequence(WmOptionalPaint, "ShowWindow(SW_SHOW):overlapped already visible", FALSE);
5189
5190 SetWindowPos(hwnd, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5191 ok_sequence(WmSWP_HideOverlappedSeq, "SetWindowPos:SWP_HIDEWINDOW:overlapped", FALSE);
5192 ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n");
5193 ok(GetActiveWindow() == hwnd, "window should still be active\n");
5194
5195 /* test WM_SETREDRAW on a visible top level window */
5196 ShowWindow(hwnd, SW_SHOW);
5197 flush_events();
5198 test_WM_SETREDRAW(hwnd);
5199
5200 trace("testing scroll APIs on a visible top level window %p\n", hwnd);
5201 test_scroll_messages(hwnd);
5202
5203 /* test resizing and moving */
5204 SetWindowPos( hwnd, 0, 0, 0, 300, 300, SWP_NOMOVE|SWP_NOACTIVATE );
5205 ok_sequence(WmSWP_ResizeSeq, "SetWindowPos:Resize", FALSE );
5206 flush_events();
5207 flush_sequence();
5208 SetWindowPos( hwnd, 0, 200, 200, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE );
5209 ok_sequence(WmSWP_MoveSeq, "SetWindowPos:Move", FALSE );
5210 flush_events();
5211 flush_sequence();
5212 SetWindowPos( hwnd, 0, 200, 200, 250, 250, SWP_NOZORDER|SWP_NOACTIVATE );
5213 ok_sequence(WmSWP_ResizeNoZOrder, "SetWindowPos:WmSWP_ResizeNoZOrder", FALSE );
5214 flush_events();
5215 flush_sequence();
5216
5217 /* popups don't get WM_GETMINMAXINFO */
5218 SetWindowLongW( hwnd, GWL_STYLE, WS_VISIBLE|WS_POPUP );
5219 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
5220 flush_sequence();
5221 SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOACTIVATE );
5222 ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
5223
5224 DestroyWindow(hwnd);
5225 ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
5226
5227 /* Test if windows are correctly drawn when first shown */
5228
5229 /* Visible, redraw */
5230 flush_events();
5231 flush_sequence();
5232 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5233 10, 10, 100, 100, NULL, 0, 0, NULL );
5234 ok (hwnd != 0, "Failed to create popup window\n");
5235 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5236 ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_visible", FALSE);
5237 DestroyWindow(hwnd);
5238
5239 /* Invisible, show, message */
5240 flush_events();
5241 flush_sequence();
5242 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5243 10, 10, 100, 100, NULL, 0, 0, NULL );
5244 ok (hwnd != 0, "Failed to create popup window\n");
5245 ShowWindow(hwnd, SW_SHOW);
5246 SendMessageW(hwnd, WM_PAINT, 0, 0);
5247 ok_sequence(WmShowPopupFirstDrawSeq_1, "RedrawWindow:show_popup_first_draw_show", FALSE);
5248 DestroyWindow(hwnd);
5249
5250 /* Invisible, show maximized, redraw */
5251 flush_events();
5252 flush_sequence();
5253 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP,
5254 10, 10, 100, 100, NULL, 0, 0, NULL );
5255 ok (hwnd != 0, "Failed to create popup window\n");
5256 ShowWindow(hwnd, SW_SHOWMAXIMIZED);
5257 RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW);
5258 ok_sequence(WmShowPopupFirstDrawSeq_2, "RedrawWindow:show_popup_first_draw_show_maximized", FALSE);
5259 DestroyWindow(hwnd);
5260
5261 /* Test SetWindowPos */
5262 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW, FALSE);
5263 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, 0, FALSE);
5264 test_msg_setpos(WmFirstDrawSetWindowPosSeq3,
5265 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER, FALSE);
5266
5267 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOSIZE, FALSE);
5268 test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOMOVE, FALSE);
5269 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTSIZE, FALSE);
5270 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCLIENTMOVE, FALSE);
5271 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOZORDER, FALSE);
5272
5273 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE, FALSE);
5274 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTMOVE, FALSE);
5275 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOCLIENTSIZE, FALSE);
5276 test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOMOVE, FALSE);
5277 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOSIZE, FALSE);
5278 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_DEFERERASE | SWP_NOZORDER, FALSE);
5279
5280 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS, FALSE);
5281 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTMOVE, FALSE);
5282 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOCLIENTSIZE, FALSE);
5283 test_msg_setpos(WmFirstDrawSetWindowPosSeq4, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOMOVE, FALSE);
5284 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOSIZE, FALSE);
5285 test_msg_setpos(WmFirstDrawSetWindowPosSeq1, SWP_SHOWWINDOW | SWP_NOCOPYBITS | SWP_NOZORDER, FALSE);
5286
5287 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW, FALSE);
5288 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTMOVE, FALSE);
5289 test_msg_setpos(WmFirstDrawSetWindowPosSeq3, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCLIENTSIZE, FALSE);
5290 test_msg_setpos(WmFirstDrawSetWindowPosSeq5, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOMOVE, FALSE);
5291 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOSIZE, FALSE);
5292 test_msg_setpos(WmFirstDrawSetWindowPosSeq2, SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOZORDER, FALSE);
5293
5294 /* Test SetWindowPos with child windows */
5295 flush_events();
5296 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5297 100, 100, 200, 200, 0, 0, 0, NULL);
5298 ok (hparent != 0, "Failed to create parent window\n");
5299
5300 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5301 0, 0, 10, 10, hparent, 0, 0, NULL);
5302 ok (hchild != 0, "Failed to create child window\n");
5303 flush_sequence();
5304 SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5305 ok_sequence(WmFirstDrawChildSeq1, /* Expect no messages for the child */
5306 "SetWindowPos:show_popup_first_show_window_child1", FALSE);
5307 DestroyWindow(hchild);
5308 DestroyWindow(hparent);
5309
5310 flush_events();
5311 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
5312 100, 100, 200, 200, 0, 0, 0, NULL);
5313 ok (hparent != 0, "Failed to create parent window\n");
5314
5315 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5316 0, 0, 10, 10, hparent, 0, 0, NULL);
5317 ok (hchild != 0, "Failed to create child window\n");
5318 flush_sequence();
5319 SetWindowPos(hparent, NULL, 0, 0, 100, 100, SWP_SHOWWINDOW);
5320 ok_sequence(WmFirstDrawChildSeq2, /* Expect child to be redrawn */
5321 "SetWindowPos:show_popup_first_show_window_child2", FALSE);
5322 DestroyWindow(hchild);
5323 DestroyWindow(hparent);
5324
5325 /* Test message sequence for extreme position and size */
5326
5327 flush_sequence();
5328 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5329 -10, -10, 10000, 10000, NULL, 0, 0, NULL );
5330 ok (hwnd != 0, "Failed to create popup window\n");
5331 ok_sequence(WmShowPopupExtremeLocationSeq, "RedrawWindow:show_popup_extreme_location", TRUE);
5332 DestroyWindow(hwnd);
5333
5334
5335 /* Test child windows */
5336
5337 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5338 100, 100, 200, 200, 0, 0, 0, NULL);
5339 ok (hparent != 0, "Failed to create parent window\n");
5340 flush_sequence();
5341
5342 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_MAXIMIZE,
5343 0, 0, 10, 10, hparent, 0, 0, NULL);
5344 ok (hchild != 0, "Failed to create child window\n");
5345 ok_sequence(WmCreateMaximizedChildSeq, "CreateWindow:maximized child", FALSE);
5346 DestroyWindow(hchild);
5347 flush_sequence();
5348
5349 /* visible child window with a caption */
5350 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
5351 WS_CHILD | WS_VISIBLE | WS_CAPTION,
5352 0, 0, 10, 10, hparent, 0, 0, NULL);
5353 ok (hchild != 0, "Failed to create child window\n");
5354 ok_sequence(WmCreateVisibleChildSeq, "CreateWindow:visible child", FALSE);
5355
5356 trace("testing scroll APIs on a visible child window %p\n", hchild);
5357 test_scroll_messages(hchild);
5358
5359 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5360 ok_sequence(WmShowChildSeq_4, "SetWindowPos(SWP_SHOWWINDOW):child with a caption", FALSE);
5361
5362 DestroyWindow(hchild);
5363 flush_sequence();
5364
5365 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5366 0, 0, 10, 10, hparent, 0, 0, NULL);
5367 ok (hchild != 0, "Failed to create child window\n");
5368 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5369
5370 hchild2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2", WS_CHILD,
5371 100, 100, 50, 50, hparent, 0, 0, NULL);
5372 ok (hchild2 != 0, "Failed to create child2 window\n");
5373 flush_sequence();
5374
5375 hbutton = CreateWindowExA(0, "TestWindowClass", "Test button", WS_CHILD,
5376 0, 100, 50, 50, hchild, 0, 0, NULL);
5377 ok (hbutton != 0, "Failed to create button window\n");
5378
5379 /* test WM_SETREDRAW on a not visible child window */
5380 test_WM_SETREDRAW(hchild);
5381
5382 ShowWindow(hchild, SW_SHOW);
5383 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5384
5385 /* check parent messages too */
5386 log_all_parent_messages++;
5387 ShowWindow(hchild, SW_HIDE);
5388 ok_sequence(WmHideChildSeq2, "ShowWindow(SW_HIDE):child", FALSE);
5389 log_all_parent_messages--;
5390
5391 ShowWindow(hchild, SW_SHOW);
5392 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5393
5394 ShowWindow(hchild, SW_HIDE);
5395 ok_sequence(WmHideChildSeq, "ShowWindow(SW_HIDE):child", FALSE);
5396
5397 ShowWindow(hchild, SW_SHOW);
5398 ok_sequence(WmShowChildSeq, "ShowWindow(SW_SHOW):child", FALSE);
5399
5400 /* test WM_SETREDRAW on a visible child window */
5401 test_WM_SETREDRAW(hchild);
5402
5403 log_all_parent_messages++;
5404 MoveWindow(hchild, 10, 10, 20, 20, TRUE);
5405 ok_sequence(WmResizingChildWithMoveWindowSeq, "MoveWindow:child", FALSE);
5406 log_all_parent_messages--;
5407
5408 ShowWindow(hchild, SW_HIDE);
5409 flush_sequence();
5410 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5411 ok_sequence(WmShowChildSeq_2, "SetWindowPos:show_child_2", FALSE);
5412
5413 ShowWindow(hchild, SW_HIDE);
5414 flush_sequence();
5415 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
5416 ok_sequence(WmShowChildSeq_3, "SetWindowPos:show_child_3", FALSE);
5417
5418 /* DestroyWindow sequence below expects that a child has focus */
5419 SetFocus(hchild);
5420 flush_sequence();
5421
5422 DestroyWindow(hchild);
5423 ok_sequence(WmDestroyChildSeq, "DestroyWindow:child", FALSE);
5424 DestroyWindow(hchild2);
5425 DestroyWindow(hbutton);
5426
5427 flush_sequence();
5428 hchild = CreateWindowExA(0, "TestWindowClass", "Test Child Popup", WS_CHILD | WS_POPUP,
5429 0, 0, 100, 100, hparent, 0, 0, NULL);
5430 ok (hchild != 0, "Failed to create child popup window\n");
5431 ok_sequence(WmCreateChildPopupSeq, "CreateWindow:child_popup", FALSE);
5432 DestroyWindow(hchild);
5433
5434 /* test what happens to a window which sets WS_VISIBLE in WM_CREATE */
5435 flush_sequence();
5436 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP,
5437 0, 0, 100, 100, hparent, 0, 0, NULL);
5438 ok (hchild != 0, "Failed to create popup window\n");
5439 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5440 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5441 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5442 flush_sequence();
5443 ShowWindow(hchild, SW_SHOW);
5444 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5445 flush_sequence();
5446 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5447 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5448 flush_sequence();
5449 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE);
5450 ok_sequence(WmShowVisiblePopupSeq_3, "SetWindowPos:show_visible_popup_3", FALSE);
5451 DestroyWindow(hchild);
5452
5453 /* this time add WS_VISIBLE for CreateWindowEx, but this fact actually
5454 * changes nothing in message sequences.
5455 */
5456 flush_sequence();
5457 hchild = CreateWindowExA(0, "TestPopupClass", "Test Popup", WS_POPUP | WS_VISIBLE,
5458 0, 0, 100, 100, hparent, 0, 0, NULL);
5459 ok (hchild != 0, "Failed to create popup window\n");
5460 ok_sequence(WmCreateInvisiblePopupSeq, "CreateWindow:invisible_popup", FALSE);
5461 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5462 ok(IsWindowVisible(hchild), "IsWindowVisible() should return TRUE\n");
5463 flush_sequence();
5464 ShowWindow(hchild, SW_SHOW);
5465 ok_sequence(WmEmptySeq, "ShowWindow:show_visible_popup", FALSE);
5466 flush_sequence();
5467 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5468 ok_sequence(WmShowVisiblePopupSeq_2, "SetWindowPos:show_visible_popup_2", FALSE);
5469 DestroyWindow(hchild);
5470
5471 flush_sequence();
5472 hwnd = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
5473 0, 0, 100, 100, hparent, 0, 0, NULL);
5474 ok(hwnd != 0, "Failed to create custom dialog window\n");
5475 ok_sequence(WmCreateCustomDialogSeq, "CreateCustomDialog", TRUE);
5476
5477 if(0) {
5478 trace("testing scroll APIs on a visible dialog %p\n", hwnd);
5479 test_scroll_messages(hwnd);
5480 }
5481
5482 flush_sequence();
5483
5484 test_def_id = TRUE;
5485 SendMessageA(hwnd, WM_NULL, 0, 0);
5486
5487 flush_sequence();
5488 after_end_dialog = TRUE;
5489 EndDialog( hwnd, 0 );
5490 ok_sequence(WmEndCustomDialogSeq, "EndCustomDialog", FALSE);
5491
5492 DestroyWindow(hwnd);
5493 after_end_dialog = FALSE;
5494 test_def_id = FALSE;
5495
5496 ok(GetCursorPos(&pos), "GetCursorPos failed\n");
5497 ok(SetCursorPos(109, 109), "SetCursorPos failed\n");
5498
5499 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_POPUP|WS_CHILD,
5500 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL);
5501 ok(hwnd != 0, "Failed to create custom dialog window\n");
5502 flush_sequence();
5503 trace("call ShowWindow(%p, SW_SHOW)\n", hwnd);
5504 ShowWindow(hwnd, SW_SHOW);
5505 ok_sequence(WmShowCustomDialogSeq, "ShowCustomDialog", TRUE);
5506
5507 flush_events();
5508 flush_sequence();
5509 ret = DrawMenuBar(hwnd);
5510 ok(ret, "DrawMenuBar failed: %d\n", GetLastError());
5511 flush_events();
5512 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5513 ok(SetCursorPos(pos.x, pos.y), "SetCursorPos failed\n");
5514
5515 DestroyWindow(hwnd);
5516
5517 hwnd = CreateWindowExA(0, "TestDialogClass", NULL, WS_CHILD|WS_VISIBLE,
5518 0, 0, 100, 100, hparent, 0, GetModuleHandleA(0), NULL);
5519 ok(hwnd != 0, "Failed to create custom dialog window\n");
5520 flush_events();
5521 flush_sequence();
5522 ret = DrawMenuBar(hwnd);
5523 ok(ret, "DrawMenuBar failed: %d\n", GetLastError());
5524 flush_events();
5525 ok_sequence(WmEmptySeq, "DrawMenuBar for a child window", FALSE);
5526
5527 DestroyWindow(hwnd);
5528
5529 flush_sequence();
5530 DialogBoxA( 0, "TEST_DIALOG", hparent, TestModalDlgProcA );
5531 ok_sequence(WmModalDialogSeq, "ModalDialog", TRUE);
5532
5533 DestroyWindow(hparent);
5534 flush_sequence();
5535
5536 /* Message sequence for SetMenu */
5537 ok(!DrawMenuBar(hwnd), "DrawMenuBar should return FALSE for a destroyed window\n");
5538 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "last error is %d\n", GetLastError());
5539 ok_sequence(WmEmptySeq, "DrawMenuBar for a window without a menu", FALSE);
5540
5541 hmenu = CreateMenu();
5542 ok (hmenu != 0, "Failed to create menu\n");
5543 ok (InsertMenuA(hmenu, -1, MF_BYPOSITION, 0x1000, "foo"), "InsertMenu failed\n");
5544 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
5545 100, 100, 200, 200, 0, hmenu, 0, NULL);
5546 ok_sequence(WmCreateOverlappedSeq, "CreateWindow:overlapped", FALSE);
5547 ok (SetMenu(hwnd, 0), "SetMenu\n");
5548 ok_sequence(WmSetMenuNonVisibleSizeChangeSeq, "SetMenu:NonVisibleSizeChange", FALSE);
5549 ok (SetMenu(hwnd, 0), "SetMenu\n");
5550 ok_sequence(WmSetMenuNonVisibleNoSizeChangeSeq, "SetMenu:NonVisibleNoSizeChange", FALSE);
5551 ShowWindow(hwnd, SW_SHOW);
5552 UpdateWindow( hwnd );
5553 flush_events();
5554 flush_sequence();
5555 ok (SetMenu(hwnd, 0), "SetMenu\n");
5556 ok_sequence(WmSetMenuVisibleNoSizeChangeSeq, "SetMenu:VisibleNoSizeChange", FALSE);
5557 ok (SetMenu(hwnd, hmenu), "SetMenu\n");
5558 ok_sequence(WmSetMenuVisibleSizeChangeSeq, "SetMenu:VisibleSizeChange", FALSE);
5559
5560 UpdateWindow( hwnd );
5561 flush_events();
5562 flush_sequence();
5563 ok(DrawMenuBar(hwnd), "DrawMenuBar\n");
5564 flush_events();
5565 ok_sequence(WmDrawMenuBarSeq, "DrawMenuBar", FALSE);
5566
5567 DestroyWindow(hwnd);
5568 flush_sequence();
5569
5570 /* Message sequence for EnableWindow */
5571 hparent = CreateWindowExA(0, "TestWindowClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
5572 100, 100, 200, 200, 0, 0, 0, NULL);
5573 ok (hparent != 0, "Failed to create parent window\n");
5574 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
5575 0, 0, 10, 10, hparent, 0, 0, NULL);
5576 ok (hchild != 0, "Failed to create child window\n");
5577
5578 SetFocus(hchild);
5579 flush_events();
5580 flush_sequence();
5581
5582 EnableWindow(hparent, FALSE);
5583 ok_sequence(WmEnableWindowSeq_1, "EnableWindow(FALSE)", FALSE);
5584
5585 EnableWindow(hparent, FALSE);
5586 ok_sequence(WmEnableWindowSeq_2, "EnableWindow(FALSE)", FALSE);
5587
5588 EnableWindow(hparent, TRUE);
5589 ok_sequence(WmEnableWindowSeq_3, "EnableWindow(TRUE)", FALSE);
5590
5591 EnableWindow(hparent, TRUE);
5592 ok_sequence(WmEnableWindowSeq_4, "EnableWindow(TRUE)", FALSE);
5593
5594 flush_events();
5595 flush_sequence();
5596
5597 test_MsgWaitForMultipleObjects(hparent);
5598 test_WM_DEVICECHANGE(hparent);
5599
5600 /* the following test causes an exception in user.exe under win9x */
5601 if (!PostMessageW( hparent, WM_USER, 0, 0 ))
5602 {
5603 DestroyWindow(hparent);
5604 flush_sequence();
5605 return;
5606 }
5607 PostMessageW( hparent, WM_USER+1, 0, 0 );
5608 /* PeekMessage(NULL) fails, but still removes the message */
5609 SetLastError(0xdeadbeef);
5610 ok( !PeekMessageW( NULL, 0, 0, 0, PM_REMOVE ), "PeekMessage(NULL) should fail\n" );
5611 ok( GetLastError() == ERROR_NOACCESS || /* Win2k */
5612 GetLastError() == 0xdeadbeef, /* NT4 */
5613 "last error is %d\n", GetLastError() );
5614 ok( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ), "PeekMessage should succeed\n" );
5615 ok( msg.message == WM_USER+1, "got %x instead of WM_USER+1\n", msg.message );
5616
5617 DestroyWindow(hchild);
5618 DestroyWindow(hparent);
5619 flush_sequence();
5620
5621 /* Message sequences for WM_SETICON */
5622 trace("testing WM_SETICON\n");
5623 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
5624 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5625 NULL, NULL, 0);
5626 ShowWindow(hwnd, SW_SHOW);
5627 UpdateWindow(hwnd);
5628 flush_events();
5629 flush_sequence();
5630 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5631 ok_sequence(WmSetIcon_1, "WM_SETICON for shown window with caption", FALSE);
5632
5633 ShowWindow(hwnd, SW_HIDE);
5634 flush_events();
5635 flush_sequence();
5636 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5637 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window with caption", FALSE);
5638 DestroyWindow(hwnd);
5639 flush_sequence();
5640
5641 hwnd = CreateWindowExA(0, "TestPopupClass", NULL, WS_POPUP,
5642 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
5643 NULL, NULL, 0);
5644 ShowWindow(hwnd, SW_SHOW);
5645 UpdateWindow(hwnd);
5646 flush_events();
5647 flush_sequence();
5648 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5649 ok_sequence(WmSetIcon_2, "WM_SETICON for shown window without caption", FALSE);
5650
5651 ShowWindow(hwnd, SW_HIDE);
5652 flush_events();
5653 flush_sequence();
5654 SendMessageA(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIconA(0, (LPCSTR)IDI_APPLICATION));
5655 ok_sequence(WmSetIcon_2, "WM_SETICON for hidden window without caption", FALSE);
5656
5657 flush_sequence();
5658 res = SendMessageA(hwnd, 0x3B, 0x8000000b, 0);
5659 if (!res)
5660 {
5661 todo_wine win_skip( "Message 0x3b not supported\n" );
5662 goto done;
5663 }
5664 ok_sequence(WmInitEndSession, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x8000000b", TRUE);
5665 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x8000000b, 0) should have returned 1 instead of %ld\n", res);
5666 res = SendMessageA(hwnd, 0x3B, 0x0000000b, 0);
5667 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000b", TRUE);
5668 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000b, 0) should have returned 1 instead of %ld\n", res);
5669 res = SendMessageA(hwnd, 0x3B, 0x0000000f, 0);
5670 ok_sequence(WmInitEndSession_2, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x0000000f", TRUE);
5671 ok(res == 1, "SendMessage(hwnd, 0x3B, 0x0000000f, 0) should have returned 1 instead of %ld\n", res);
5672
5673 flush_sequence();
5674 res = SendMessageA(hwnd, 0x3B, 0x80000008, 0);
5675 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000008", TRUE);
5676 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000008, 0) should have returned 2 instead of %ld\n", res);
5677 res = SendMessageA(hwnd, 0x3B, 0x00000008, 0);
5678 ok_sequence(WmInitEndSession_4, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x00000008", TRUE);
5679 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x00000008, 0) should have returned 2 instead of %ld\n", res);
5680
5681 res = SendMessageA(hwnd, 0x3B, 0x80000004, 0);
5682 ok_sequence(WmInitEndSession_3, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000004", TRUE);
5683 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000004, 0) should have returned 2 instead of %ld\n", res);
5684
5685 res = SendMessageA(hwnd, 0x3B, 0x80000001, 0);
5686 ok_sequence(WmInitEndSession_5, "Handling of undocumented 0x3B message by DefWindowProc wparam=0x80000001", TRUE);
5687 ok(res == 2, "SendMessage(hwnd, 0x3B, 0x80000001, 0) should have returned 2 instead of %ld\n", res);
5688
5689 done:
5690 DestroyWindow(hwnd);
5691 flush_sequence();
5692 }
5693
5694 static void test_setwindowpos(void)
5695 {
5696 HWND hwnd;
5697 RECT rc;
5698 LRESULT res;
5699 const INT winX = 100;
5700 const INT winY = 100;
5701 const INT sysX = GetSystemMetrics(SM_CXMINTRACK);
5702
5703 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
5704 0, 0, winX, winY, 0,
5705 NULL, NULL, 0);
5706
5707 GetWindowRect(hwnd, &rc);
5708 expect(sysX, rc.right);
5709 expect(winY, rc.bottom);
5710
5711 flush_events();
5712 flush_sequence();
5713 res = SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, winX, winY, 0);
5714 ok_sequence(WmZOrder, "Z-Order", TRUE);
5715 ok(res == TRUE, "SetWindowPos expected TRUE, got %ld\n", res);
5716
5717 GetWindowRect(hwnd, &rc);
5718 expect(sysX, rc.right);
5719 expect(winY, rc.bottom);
5720 DestroyWindow(hwnd);
5721 }
5722
5723 static void invisible_parent_tests(void)
5724 {
5725 HWND hparent, hchild;
5726
5727 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
5728 100, 100, 200, 200, 0, 0, 0, NULL);
5729 ok (hparent != 0, "Failed to create parent window\n");
5730 flush_sequence();
5731
5732 /* test showing child with hidden parent */
5733
5734 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5735 0, 0, 10, 10, hparent, 0, 0, NULL);
5736 ok (hchild != 0, "Failed to create child window\n");
5737 ok_sequence(WmCreateChildSeq, "CreateWindow:child", FALSE);
5738
5739 ShowWindow( hchild, SW_MINIMIZE );
5740 ok_sequence(WmShowChildInvisibleParentSeq_1, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
5741 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5742 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5743
5744 /* repeat */
5745 flush_events();
5746 flush_sequence();
5747 ShowWindow( hchild, SW_MINIMIZE );
5748 ok_sequence(WmShowChildInvisibleParentSeq_1r, "ShowWindow(SW_MINIMIZE) child with invisible parent", FALSE);
5749
5750 DestroyWindow(hchild);
5751 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5752 0, 0, 10, 10, hparent, 0, 0, NULL);
5753 flush_sequence();
5754
5755 ShowWindow( hchild, SW_MAXIMIZE );
5756 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5757 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5758 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5759
5760 /* repeat */
5761 flush_events();
5762 flush_sequence();
5763 ShowWindow( hchild, SW_MAXIMIZE );
5764 ok_sequence(WmShowChildInvisibleParentSeq_2r, "ShowWindow(SW_MAXIMIZE) child with invisible parent", FALSE);
5765
5766 DestroyWindow(hchild);
5767 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5768 0, 0, 10, 10, hparent, 0, 0, NULL);
5769 flush_sequence();
5770
5771 ShowWindow( hchild, SW_RESTORE );
5772 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_RESTORE) child with invisible parent", FALSE);
5773 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5774 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5775
5776 DestroyWindow(hchild);
5777 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5778 0, 0, 10, 10, hparent, 0, 0, NULL);
5779 flush_sequence();
5780
5781 ShowWindow( hchild, SW_SHOWMINIMIZED );
5782 ok_sequence(WmShowChildInvisibleParentSeq_3, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5783 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5784 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5785
5786 /* repeat */
5787 flush_events();
5788 flush_sequence();
5789 ShowWindow( hchild, SW_SHOWMINIMIZED );
5790 ok_sequence(WmShowChildInvisibleParentSeq_3r, "ShowWindow(SW_SHOWMINIMIZED) child with invisible parent", FALSE);
5791
5792 DestroyWindow(hchild);
5793 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5794 0, 0, 10, 10, hparent, 0, 0, NULL);
5795 flush_sequence();
5796
5797 /* same as ShowWindow( hchild, SW_MAXIMIZE ); */
5798 ShowWindow( hchild, SW_SHOWMAXIMIZED );
5799 ok_sequence(WmShowChildInvisibleParentSeq_2, "ShowWindow(SW_SHOWMAXIMIZED) child with invisible parent", FALSE);
5800 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5801 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5802
5803 DestroyWindow(hchild);
5804 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5805 0, 0, 10, 10, hparent, 0, 0, NULL);
5806 flush_sequence();
5807
5808 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5809 ok_sequence(WmShowChildInvisibleParentSeq_4, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5810 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5811 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5812
5813 /* repeat */
5814 flush_events();
5815 flush_sequence();
5816 ShowWindow( hchild, SW_SHOWMINNOACTIVE );
5817 ok_sequence(WmShowChildInvisibleParentSeq_4r, "ShowWindow(SW_SHOWMINNOACTIVE) child with invisible parent", FALSE);
5818
5819 DestroyWindow(hchild);
5820 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5821 0, 0, 10, 10, hparent, 0, 0, NULL);
5822 flush_sequence();
5823
5824 /* FIXME: looks like XP SP2 doesn't know about SW_FORCEMINIMIZE at all */
5825 ShowWindow( hchild, SW_FORCEMINIMIZE );
5826 ok_sequence(WmEmptySeq, "ShowWindow(SW_FORCEMINIMIZE) child with invisible parent", TRUE);
5827 todo_wine {
5828 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5829 }
5830 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5831
5832 DestroyWindow(hchild);
5833 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5834 0, 0, 10, 10, hparent, 0, 0, NULL);
5835 flush_sequence();
5836
5837 ShowWindow( hchild, SW_SHOWNA );
5838 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5839 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5840 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5841
5842 /* repeat */
5843 flush_events();
5844 flush_sequence();
5845 ShowWindow( hchild, SW_SHOWNA );
5846 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOWNA) child with invisible parent", FALSE);
5847
5848 DestroyWindow(hchild);
5849 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD,
5850 0, 0, 10, 10, hparent, 0, 0, NULL);
5851 flush_sequence();
5852
5853 ShowWindow( hchild, SW_SHOW );
5854 ok_sequence(WmShowChildInvisibleParentSeq_5, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5855 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5856 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5857
5858 /* repeat */
5859 flush_events();
5860 flush_sequence();
5861 ShowWindow( hchild, SW_SHOW );
5862 ok_sequence(WmEmptySeq, "ShowWindow(SW_SHOW) child with invisible parent", FALSE);
5863
5864 ShowWindow( hchild, SW_HIDE );
5865 ok_sequence(WmHideChildInvisibleParentSeq, "ShowWindow:hide child with invisible parent", FALSE);
5866 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should be not set\n");
5867 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5868
5869 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5870 ok_sequence(WmShowChildInvisibleParentSeq_6, "SetWindowPos:show child with invisible parent", FALSE);
5871 ok(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
5872 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5873
5874 SetWindowPos(hchild, 0,0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5875 ok_sequence(WmHideChildInvisibleParentSeq_2, "SetWindowPos:hide child with invisible parent", FALSE);
5876 ok(!(GetWindowLongA(hchild, GWL_STYLE) & WS_VISIBLE), "WS_VISIBLE should not be set\n");
5877 ok(!IsWindowVisible(hchild), "IsWindowVisible() should return FALSE\n");
5878
5879 SetWindowPos(hchild, 0,0,0,0,0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
5880 flush_sequence();
5881 DestroyWindow(hchild);
5882 ok_sequence(WmDestroyInvisibleChildSeq, "DestroyInvisibleChildSeq", FALSE);
5883
5884 DestroyWindow(hparent);
5885 flush_sequence();
5886 }
5887
5888 /****************** button message test *************************/
5889 #define ID_BUTTON 0x000e
5890
5891 static const struct message WmSetFocusButtonSeq[] =
5892 {
5893 { HCBT_SETFOCUS, hook },
5894 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5895 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5896 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5897 { WM_SETFOCUS, sent|wparam, 0 },
5898 { WM_CTLCOLORBTN, sent|parent },
5899 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5900 { WM_APP, sent|wparam|lparam, 0, 0 },
5901 { 0 }
5902 };
5903 static const struct message WmKillFocusButtonSeq[] =
5904 {
5905 { HCBT_SETFOCUS, hook },
5906 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5907 { WM_KILLFOCUS, sent|wparam, 0 },
5908 { WM_CTLCOLORBTN, sent|parent },
5909 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5910 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5911 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5912 { WM_APP, sent|wparam|lparam, 0, 0 },
5913 { WM_PAINT, sent },
5914 { WM_CTLCOLORBTN, sent|parent },
5915 { 0 }
5916 };
5917 static const struct message WmSetFocusStaticSeq[] =
5918 {
5919 { HCBT_SETFOCUS, hook },
5920 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5921 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5922 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5923 { WM_SETFOCUS, sent|wparam, 0 },
5924 { WM_CTLCOLORSTATIC, sent|parent },
5925 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5926 { WM_COMMAND, sent|wparam|parent|optional, MAKEWPARAM(ID_BUTTON, BN_CLICKED) }, /* radio button */
5927 { WM_APP, sent|wparam|lparam, 0, 0 },
5928 { 0 }
5929 };
5930 static const struct message WmKillFocusStaticSeq[] =
5931 {
5932 { HCBT_SETFOCUS, hook },
5933 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5934 { WM_KILLFOCUS, sent|wparam, 0 },
5935 { WM_CTLCOLORSTATIC, sent|parent },
5936 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5937 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5938 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5939 { WM_APP, sent|wparam|lparam, 0, 0 },
5940 { WM_PAINT, sent },
5941 { WM_CTLCOLORSTATIC, sent|parent },
5942 { 0 }
5943 };
5944 static const struct message WmSetFocusOwnerdrawSeq[] =
5945 {
5946 { HCBT_SETFOCUS, hook },
5947 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
5948 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5949 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5950 { WM_SETFOCUS, sent|wparam, 0 },
5951 { WM_CTLCOLORBTN, sent|parent },
5952 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x001040e4 },
5953 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_SETFOCUS) },
5954 { WM_APP, sent|wparam|lparam, 0, 0 },
5955 { 0 }
5956 };
5957 static const struct message WmKillFocusOwnerdrawSeq[] =
5958 {
5959 { HCBT_SETFOCUS, hook },
5960 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5961 { WM_KILLFOCUS, sent|wparam, 0 },
5962 { WM_CTLCOLORBTN, sent|parent },
5963 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000040e4 },
5964 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_KILLFOCUS) },
5965 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
5966 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
5967 { WM_APP, sent|wparam|lparam, 0, 0 },
5968 { WM_PAINT, sent },
5969 { WM_CTLCOLORBTN, sent|parent },
5970 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
5971 { 0 }
5972 };
5973 static const struct message WmLButtonDownSeq[] =
5974 {
5975 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5976 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5977 { HCBT_SETFOCUS, hook },
5978 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5979 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5980 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5981 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5982 { WM_CTLCOLORBTN, sent|defwinproc },
5983 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
5984 { WM_CTLCOLORBTN, sent|defwinproc },
5985 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5986 { 0 }
5987 };
5988 static const struct message WmLButtonDownStaticSeq[] =
5989 {
5990 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
5991 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
5992 { HCBT_SETFOCUS, hook },
5993 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
5994 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
5995 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
5996 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
5997 { WM_CTLCOLORSTATIC, sent|defwinproc },
5998 { BM_SETSTATE, sent|wparam|defwinproc, TRUE },
5999 { WM_CTLCOLORSTATIC, sent|defwinproc },
6000 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6001 { 0 }
6002 };
6003 static const struct message WmLButtonUpSeq[] =
6004 {
6005 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6006 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6007 { WM_CTLCOLORBTN, sent|defwinproc },
6008 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6009 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6010 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6011 { 0 }
6012 };
6013 static const struct message WmLButtonUpStaticSeq[] =
6014 {
6015 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6016 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6017 { WM_CTLCOLORSTATIC, sent|defwinproc },
6018 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6019 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6020 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6021 { 0 }
6022 };
6023 static const struct message WmLButtonUpAutoSeq[] =
6024 {
6025 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6026 { BM_SETSTATE, sent|wparam|defwinproc, FALSE },
6027 { WM_CTLCOLORSTATIC, sent|defwinproc },
6028 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6029 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6030 { BM_SETCHECK, sent|defwinproc },
6031 { WM_CTLCOLORSTATIC, sent|defwinproc, 0, 0 },
6032 { WM_CAPTURECHANGED, sent|wparam|defwinproc, 0 },
6033 { 0 }
6034 };
6035 static const struct message WmLButtonUpBrokenSeq[] =
6036 {
6037 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
6038 { 0 }
6039 };
6040 static const struct message WmSetFontButtonSeq[] =
6041 {
6042 { WM_SETFONT, sent },
6043 { WM_PAINT, sent },
6044 { WM_ERASEBKGND, sent|defwinproc|optional },
6045 { WM_CTLCOLORBTN, sent|defwinproc },
6046 { WM_CTLCOLORBTN, sent|defwinproc|optional }, /* FIXME: Wine sends it twice for BS_OWNERDRAW */
6047 { 0 }
6048 };
6049 static const struct message WmSetFontStaticSeq[] =
6050 {
6051 { WM_SETFONT, sent },
6052 { WM_PAINT, sent },
6053 { WM_ERASEBKGND, sent|defwinproc|optional },
6054 { WM_CTLCOLORSTATIC, sent|defwinproc },
6055 { 0 }
6056 };
6057 static const struct message WmSetTextButtonSeq[] =
6058 {
6059 { WM_SETTEXT, sent },
6060 { WM_CTLCOLORBTN, sent|parent },
6061 { WM_CTLCOLORBTN, sent|parent },
6062 { WM_COMMAND, sent|parent|optional },
6063 { WM_DRAWITEM, sent|parent|optional },
6064 { 0 }
6065 };
6066 static const struct message WmSetTextStaticSeq[] =
6067 {
6068 { WM_SETTEXT, sent },
6069 { WM_CTLCOLORSTATIC, sent|parent },
6070 { WM_CTLCOLORSTATIC, sent|parent },
6071 { 0 }
6072 };
6073 static const struct message WmSetTextGroupSeq[] =
6074 {
6075 { WM_SETTEXT, sent },
6076 { WM_CTLCOLORSTATIC, sent|parent },
6077 { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
6078 { WM_CTLCOLORSTATIC, sent|parent|optional }, /* FIXME: Missing in Wine */
6079 { 0 }
6080 };
6081 static const struct message WmSetTextInvisibleSeq[] =
6082 {
6083 { WM_SETTEXT, sent },
6084 { 0 }
6085 };
6086 static const struct message WmSetStyleButtonSeq[] =
6087 {
6088 { BM_SETSTYLE, sent },
6089 { WM_APP, sent|wparam|lparam, 0, 0 },
6090 { WM_PAINT, sent },
6091 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6092 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6093 { WM_CTLCOLORBTN, sent|parent },
6094 { 0 }
6095 };
6096 static const struct message WmSetStyleStaticSeq[] =
6097 {
6098 { BM_SETSTYLE, sent },
6099 { WM_APP, sent|wparam|lparam, 0, 0 },
6100 { WM_PAINT, sent },
6101 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6102 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6103 { WM_CTLCOLORSTATIC, sent|parent },
6104 { 0 }
6105 };
6106 static const struct message WmSetStyleUserSeq[] =
6107 {
6108 { BM_SETSTYLE, sent },
6109 { WM_APP, sent|wparam|lparam, 0, 0 },
6110 { WM_PAINT, sent },
6111 { WM_NCPAINT, sent|defwinproc|optional }, /* FIXME: Wine sends it */
6112 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6113 { WM_CTLCOLORBTN, sent|parent },
6114 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_PAINT) },
6115 { 0 }
6116 };
6117 static const struct message WmSetStyleOwnerdrawSeq[] =
6118 {
6119 { BM_SETSTYLE, sent },
6120 { WM_APP, sent|wparam|lparam, 0, 0 },
6121 { WM_PAINT, sent },
6122 { WM_NCPAINT, sent|optional }, /* FIXME: Wine sends it */
6123 { WM_ERASEBKGND, sent|defwinproc|optional }, /* Win9x doesn't send it */
6124 { WM_CTLCOLORBTN, sent|parent },
6125 { WM_CTLCOLORBTN, sent|parent|optional }, /* Win9x doesn't send it */
6126 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000010e4 },
6127 { 0 }
6128 };
6129 static const struct message WmSetStateButtonSeq[] =
6130 {
6131 { BM_SETSTATE, sent },
6132 { WM_CTLCOLORBTN, sent|parent },
6133 { WM_APP, sent|wparam|lparam, 0, 0 },
6134 { 0 }
6135 };
6136 static const struct message WmSetStateStaticSeq[] =
6137 {
6138 { BM_SETSTATE, sent },
6139 { WM_CTLCOLORSTATIC, sent|parent },
6140 { WM_APP, sent|wparam|lparam, 0, 0 },
6141 { 0 }
6142 };
6143 static const struct message WmSetStateUserSeq[] =
6144 {
6145 { BM_SETSTATE, sent },
6146 { WM_CTLCOLORBTN, sent|parent },
6147 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_HILITE) },
6148 { WM_APP, sent|wparam|lparam, 0, 0 },
6149 { 0 }
6150 };
6151 static const struct message WmSetStateOwnerdrawSeq[] =
6152 {
6153 { BM_SETSTATE, sent },
6154 { WM_CTLCOLORBTN, sent|parent },
6155 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000120e4 },
6156 { WM_APP, sent|wparam|lparam, 0, 0 },
6157 { 0 }
6158 };
6159 static const struct message WmClearStateButtonSeq[] =
6160 {
6161 { BM_SETSTATE, sent },
6162 { WM_CTLCOLORBTN, sent|parent },
6163 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_BUTTON, BN_UNHILITE) },
6164 { WM_APP, sent|wparam|lparam, 0, 0 },
6165 { 0 }
6166 };
6167 static const struct message WmDisableButtonSeq[] =
6168 {
6169 { WM_LBUTTONDOWN, sent },
6170 { BM_SETSTATE, sent|defwinproc },
6171 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6172 { WM_CTLCOLORBTN, sent|optional },
6173 { WM_LBUTTONUP, sent },
6174 { BM_SETSTATE, sent|defwinproc },
6175 { WM_CTLCOLORBTN, sent|defwinproc|optional },
6176 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6177 { BM_SETCHECK, sent|defwinproc|optional },
6178 { WM_CTLCOLORBTN, sent|optional },
6179 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
6180 { WM_CAPTURECHANGED, sent|defwinproc },
6181 { WM_COMMAND, sent },
6182 { 0 }
6183 };
6184 static const struct message WmClearStateOwnerdrawSeq[] =
6185 {
6186 { BM_SETSTATE, sent },
6187 { WM_CTLCOLORBTN, sent|parent },
6188 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_BUTTON, 0x000020e4 },
6189 { WM_APP, sent|wparam|lparam, 0, 0 },
6190 { 0 }
6191 };
6192 static const struct message WmSetCheckIgnoredSeq[] =
6193 {
6194 { BM_SETCHECK, sent },
6195 { WM_APP, sent|wparam|lparam, 0, 0 },
6196 { 0 }
6197 };
6198 static const struct message WmSetCheckStaticSeq[] =
6199 {
6200 { BM_SETCHECK, sent },
6201 { WM_CTLCOLORSTATIC, sent|parent },
6202 { WM_APP, sent|wparam|lparam, 0, 0 },
6203 { 0 }
6204 };
6205
6206 static WNDPROC old_button_proc;
6207
6208 static LRESULT CALLBACK button_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
6209 {
6210 static LONG defwndproc_counter = 0;
6211 LRESULT ret;
6212 struct recvd_message msg;
6213
6214 if (ignore_message( message )) return 0;
6215
6216 switch (message)
6217 {
6218 case WM_SYNCPAINT:
6219 break;
6220 case BM_SETSTATE:
6221 if (GetCapture())
6222 ok(GetCapture() == hwnd, "GetCapture() = %p\n", GetCapture());
6223
6224 lParam = (ULONG_PTR)GetMenu(hwnd);
6225 goto log_it;
6226
6227 case WM_GETDLGCODE:
6228 if (lParam)
6229 {
6230 MSG *msg = (MSG *)lParam;
6231 lParam = MAKELPARAM(msg->message, msg->wParam);
6232 }
6233 wParam = (ULONG_PTR)GetMenu(hwnd);
6234 goto log_it;
6235
6236 case BM_SETCHECK:
6237 case BM_GETCHECK:
6238 lParam = (ULONG_PTR)GetMenu(hwnd);
6239 /* fall through */
6240 log_it:
6241 default:
6242 msg.hwnd = hwnd;
6243 msg.message = message;
6244 msg.flags = sent|wparam|lparam;
6245 if (defwndproc_counter) msg.flags |= defwinproc;
6246 msg.wParam = wParam;
6247 msg.lParam = lParam;
6248 msg.descr = "button";
6249 add_message(&msg);
6250 }
6251
6252 defwndproc_counter++;
6253 ret = CallWindowProcA(old_button_proc, hwnd, message, wParam, lParam);
6254 defwndproc_counter--;
6255
6256 return ret;
6257 }
6258
6259 static void subclass_button(void)
6260 {
6261 WNDCLASSA cls;
6262
6263 if (!GetClassInfoA(0, "button", &cls)) assert(0);
6264
6265 old_button_proc = cls.lpfnWndProc;
6266
6267 cls.hInstance = GetModuleHandleA(NULL);
6268 cls.lpfnWndProc = button_hook_proc;
6269 cls.lpszClassName = "my_button_class";
6270 UnregisterClassA(cls.lpszClassName, cls.hInstance);
6271 if (!RegisterClassA(&cls)) assert(0);
6272 }
6273
6274 static void test_button_messages(void)
6275 {
6276 static const struct
6277 {
6278 DWORD style;
6279 DWORD dlg_code;
6280 const struct message *setfocus;
6281 const struct message *killfocus;
6282 const struct message *setstyle;
6283 const struct message *setstate;
6284 const struct message *clearstate;
6285 const struct message *setcheck;
6286 const struct message *lbuttondown;
6287 const struct message *lbuttonup;
6288 const struct message *setfont;
6289 const struct message *settext;
6290 } button[] = {
6291 { BS_PUSHBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6292 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6293 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6294 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6295 WmSetTextButtonSeq },
6296 { BS_DEFPUSHBUTTON, DLGC_BUTTON | DLGC_DEFPUSHBUTTON,
6297 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleButtonSeq,
6298 WmSetStateButtonSeq, WmSetStateButtonSeq, WmSetCheckIgnoredSeq,
6299 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6300 WmSetTextButtonSeq },
6301 { BS_CHECKBOX, DLGC_BUTTON,
6302 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6303 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6304 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6305 WmSetTextStaticSeq },
6306 { BS_AUTOCHECKBOX, DLGC_BUTTON,
6307 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6308 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6309 WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6310 WmSetTextStaticSeq },
6311 { BS_RADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6312 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6313 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6314 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6315 WmSetTextStaticSeq },
6316 { BS_3STATE, DLGC_BUTTON,
6317 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6318 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6319 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6320 WmSetTextStaticSeq },
6321 { BS_AUTO3STATE, DLGC_BUTTON,
6322 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6323 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6324 WmLButtonDownStaticSeq, WmLButtonUpAutoSeq, WmSetFontStaticSeq,
6325 WmSetTextStaticSeq },
6326 { BS_GROUPBOX, DLGC_STATIC,
6327 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6328 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckIgnoredSeq,
6329 WmLButtonDownStaticSeq, WmLButtonUpStaticSeq, WmSetFontStaticSeq,
6330 WmSetTextGroupSeq },
6331 { BS_USERBUTTON, DLGC_BUTTON | DLGC_UNDEFPUSHBUTTON,
6332 WmSetFocusButtonSeq, WmKillFocusButtonSeq, WmSetStyleUserSeq,
6333 WmSetStateUserSeq, WmClearStateButtonSeq, WmSetCheckIgnoredSeq,
6334 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6335 WmSetTextButtonSeq },
6336 { BS_AUTORADIOBUTTON, DLGC_BUTTON | DLGC_RADIOBUTTON,
6337 WmSetFocusStaticSeq, WmKillFocusStaticSeq, WmSetStyleStaticSeq,
6338 WmSetStateStaticSeq, WmSetStateStaticSeq, WmSetCheckStaticSeq,
6339 NULL /* avoid infinite loop */, WmLButtonUpBrokenSeq, WmSetFontStaticSeq,
6340 WmSetTextStaticSeq },
6341 { BS_OWNERDRAW, DLGC_BUTTON,
6342 WmSetFocusOwnerdrawSeq, WmKillFocusOwnerdrawSeq, WmSetStyleOwnerdrawSeq,
6343 WmSetStateOwnerdrawSeq, WmClearStateOwnerdrawSeq, WmSetCheckIgnoredSeq,
6344 WmLButtonDownSeq, WmLButtonUpSeq, WmSetFontButtonSeq,
6345 WmSetTextButtonSeq },
6346 };
6347 LOGFONTA logfont = { 0 };
6348 HFONT zfont, hfont2;
6349 unsigned int i;
6350 HWND hwnd, parent;
6351 DWORD dlg_code;
6352
6353 /* selection with VK_SPACE should capture button window */
6354 hwnd = CreateWindowExA(0, "button", "test", BS_CHECKBOX | WS_VISIBLE | WS_POPUP,
6355 0, 0, 50, 14, 0, 0, 0, NULL);
6356 ok(hwnd != 0, "Failed to create button window\n");
6357 ReleaseCapture();
6358 SetFocus(hwnd);
6359 SendMessageA(hwnd, WM_KEYDOWN, VK_SPACE, 0);
6360 ok(GetCapture() == hwnd, "Should be captured on VK_SPACE WM_KEYDOWN\n");
6361 SendMessageA(hwnd, WM_KEYUP, VK_SPACE, 0);
6362 DestroyWindow(hwnd);
6363
6364 subclass_button();
6365
6366 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6367 100, 100, 200, 200, 0, 0, 0, NULL);
6368 ok(parent != 0, "Failed to create parent window\n");
6369
6370 memset(&logfont, 0, sizeof(logfont));
6371 logfont.lfHeight = -12;
6372 logfont.lfWeight = FW_NORMAL;
6373 strcpy(logfont.lfFaceName, "Tahoma");
6374
6375 hfont2 = CreateFontIndirectA(&logfont);
6376 ok(hfont2 != NULL, "Failed to create Tahoma font\n");
6377
6378 for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
6379 {
6380 MSG msg;
6381 DWORD style, state;
6382 HFONT prevfont;
6383 char desc[64];
6384 HDC hdc;
6385
6386 trace("button style %08x\n", button[i].style);
6387
6388 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_CHILD | BS_NOTIFY,
6389 0, 0, 50, 14, parent, (HMENU)ID_BUTTON, 0, NULL);
6390 ok(hwnd != 0, "Failed to create button window\n");
6391
6392 style = GetWindowLongA(hwnd, GWL_STYLE);
6393 style &= ~(WS_CHILD | BS_NOTIFY);
6394 /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */
6395 if (button[i].style == BS_USERBUTTON)
6396 ok(style == BS_PUSHBUTTON, "expected style BS_PUSHBUTTON got %x\n", style);
6397 else
6398 ok(style == button[i].style, "expected style %x got %x\n", button[i].style, style);
6399
6400 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
6401 ok(dlg_code == button[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
6402
6403 ShowWindow(hwnd, SW_SHOW);
6404 UpdateWindow(hwnd);
6405 SetFocus(0);
6406 flush_events();
6407 SetFocus(0);
6408 flush_sequence();
6409
6410 log_all_parent_messages++;
6411
6412 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6413 SetFocus(hwnd);
6414 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6415 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6416 ok_sequence(button[i].setfocus, "SetFocus(hwnd) on a button", FALSE);
6417
6418 SetFocus(0);
6419 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6420 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6421 ok_sequence(button[i].killfocus, "SetFocus(0) on a button", FALSE);
6422
6423 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
6424
6425 SendMessageA(hwnd, BM_SETSTYLE, button[i].style | BS_BOTTOM, TRUE);
6426 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6427 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6428 ok_sequence(button[i].setstyle, "BM_SETSTYLE on a button", FALSE);
6429
6430 style = GetWindowLongA(hwnd, GWL_STYLE);
6431 style &= ~(WS_VISIBLE | WS_CHILD | BS_NOTIFY);
6432 /* XP doesn't turn a BS_USERBUTTON into BS_PUSHBUTTON here! */
6433 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6434
6435 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6436 ok(state == 0, "expected state 0, got %04x\n", state);
6437
6438 flush_sequence();
6439
6440 SendMessageA(hwnd, BM_SETSTATE, TRUE, 0);
6441 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6442 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6443 ok_sequence(button[i].setstate, "BM_SETSTATE/TRUE on a button", FALSE);
6444
6445 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6446 ok(state == 0x0004, "expected state 0x0004, got %04x\n", state);
6447
6448 style = GetWindowLongA(hwnd, GWL_STYLE);
6449 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6450 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6451
6452 flush_sequence();
6453
6454 SendMessageA(hwnd, BM_SETSTATE, FALSE, 0);
6455 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6456 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6457 ok_sequence(button[i].clearstate, "BM_SETSTATE/FALSE on a button", FALSE);
6458
6459 state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
6460 ok(state == 0, "expected state 0, got %04x\n", state);
6461
6462 style = GetWindowLongA(hwnd, GWL_STYLE);
6463 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6464 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6465
6466 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6467 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
6468
6469 flush_sequence();
6470
6471 SendMessageA(hwnd, BM_SETCHECK, BST_UNCHECKED, 0);
6472 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6473 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6474 ok_sequence(WmSetCheckIgnoredSeq, "BM_SETCHECK on a button", FALSE);
6475
6476 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6477 ok(state == BST_UNCHECKED, "expected BST_UNCHECKED, got %04x\n", state);
6478
6479 style = GetWindowLongA(hwnd, GWL_STYLE);
6480 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6481 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6482
6483 flush_sequence();
6484
6485 SendMessageA(hwnd, BM_SETCHECK, BST_CHECKED, 0);
6486 SendMessageA(hwnd, WM_APP, 0, 0); /* place a separator mark here */
6487 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6488 ok_sequence(button[i].setcheck, "BM_SETCHECK on a button", FALSE);
6489
6490 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 1");
6491 sprintf(desc, "button[%i]: WM_SETTEXT on a visible button", i);
6492 ok_sequence(button[i].settext, desc, FALSE);
6493
6494 ShowWindow(hwnd, SW_HIDE);
6495 flush_events();
6496 flush_sequence();
6497
6498 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 2");
6499 sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
6500 ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
6501
6502 ShowWindow(hwnd, SW_SHOW);
6503 ShowWindow(parent, SW_HIDE);
6504 flush_events();
6505 flush_sequence();
6506
6507 SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"Text 3");
6508 sprintf(desc, "button[%i]: WM_SETTEXT on an invisible button", i);
6509 ok_sequence(WmSetTextInvisibleSeq, desc, FALSE);
6510
6511 ShowWindow(parent, SW_SHOW);
6512 flush_events();
6513
6514 state = SendMessageA(hwnd, BM_GETCHECK, 0, 0);
6515 if (button[i].style == BS_PUSHBUTTON ||
6516 button[i].style == BS_DEFPUSHBUTTON ||
6517 button[i].style == BS_GROUPBOX ||
6518 button[i].style == BS_USERBUTTON ||
6519 button[i].style == BS_OWNERDRAW)
6520 ok(state == BST_UNCHECKED, "expected check 0, got %04x\n", state);
6521 else
6522 ok(state == BST_CHECKED, "expected check 1, got %04x\n", state);
6523
6524 style = GetWindowLongA(hwnd, GWL_STYLE);
6525 style &= ~(WS_CHILD | BS_NOTIFY | WS_VISIBLE);
6526 if (button[i].style == BS_RADIOBUTTON ||
6527 button[i].style == BS_AUTORADIOBUTTON)
6528 ok(style == (button[i].style | WS_TABSTOP), "expected style %04x | WS_TABSTOP got %04x\n", button[i].style, style);
6529 else
6530 ok(style == button[i].style, "expected style %04x got %04x\n", button[i].style, style);
6531
6532 log_all_parent_messages--;
6533
6534 DestroyWindow(hwnd);
6535
6536 hwnd = CreateWindowExA(0, "my_button_class", "test", button[i].style | WS_POPUP | WS_VISIBLE,
6537 0, 0, 50, 14, 0, 0, 0, NULL);
6538 ok(hwnd != 0, "Failed to create button window\n");
6539
6540 SetForegroundWindow(hwnd);
6541 flush_events();
6542
6543 SetActiveWindow(hwnd);
6544 SetFocus(0);
6545 flush_sequence();
6546
6547 if (button[i].lbuttondown)
6548 {
6549 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
6550 sprintf(desc, "button[%i]: WM_LBUTTONDOWN on a button", i);
6551 ok_sequence(button[i].lbuttondown, desc, FALSE);
6552 }
6553
6554 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
6555 sprintf(desc, "button[%i]: WM_LBUTTONUP on a button", i);
6556 ok_sequence(button[i].lbuttonup, desc, FALSE);
6557
6558 flush_sequence();
6559 zfont = GetStockObject(DEFAULT_GUI_FONT);
6560 SendMessageA(hwnd, WM_SETFONT, (WPARAM)zfont, TRUE);
6561 UpdateWindow(hwnd);
6562 sprintf(desc, "button[%i]: WM_SETFONT on a button", i);
6563 ok_sequence(button[i].setfont, desc, FALSE);
6564
6565 /* Test that original font is not selected back after painting */
6566 hdc = CreateCompatibleDC(0);
6567
6568 prevfont = SelectObject(hdc, hfont2);
6569 ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
6570 SendMessageA(hwnd, WM_PRINTCLIENT, (WPARAM)hdc, 0);
6571 todo_wine
6572 ok(GetStockObject(SYSTEM_FONT) == GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PRINTCLIENT\n", i);
6573 SelectObject(hdc, prevfont);
6574
6575 prevfont = SelectObject(hdc, hfont2);
6576 ok(prevfont == GetStockObject(SYSTEM_FONT), "Unexpected default font\n");
6577 SendMessageA(hwnd, WM_PAINT, (WPARAM)hdc, 0);
6578 todo_wine
6579 ok(GetStockObject(SYSTEM_FONT) == GetCurrentObject(hdc, OBJ_FONT), "button[%u]: unexpected font selected after WM_PAINT\n", i);
6580 SelectObject(hdc, prevfont);
6581
6582 DeleteDC(hdc);
6583
6584 DestroyWindow(hwnd);
6585 }
6586
6587 DeleteObject(hfont2);
6588 DestroyWindow(parent);
6589
6590 /* Test if WM_LBUTTONDOWN and WM_LBUTTONUP to a disabled button leads to a WM_COMMAND for the parent */
6591
6592 parent = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
6593 100, 100, 200, 200, 0, 0, 0, NULL);
6594 ok (hwnd != 0, "Failed to create overlapped window\n");
6595
6596 hwnd = CreateWindowExA(0, "my_button_class", "test", BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD,
6597 0, 0, 50, 14, parent, 0, 0, NULL);
6598
6599 EnableWindow(hwnd, FALSE);
6600 flush_sequence();
6601 SendMessageA(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, 0);
6602 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
6603 ok_sequence(WmDisableButtonSeq, "Mouseclick on a disabled button", FALSE);
6604
6605 DestroyWindow(hwnd);
6606 DestroyWindow(parent);
6607 }
6608
6609 #define ID_RADIO1 501
6610 #define ID_RADIO2 502
6611 #define ID_RADIO3 503
6612 #define ID_TEXT 504
6613
6614 static const struct message auto_radio_button_BM_CLICK[] =
6615 {
6616 { BM_CLICK, sent|wparam|lparam, 0, 0 },
6617 { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 },
6618 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6619 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 },
6620 { WM_CTLCOLORSTATIC, sent|parent },
6621 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6622 { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 },
6623 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 },
6624 { WM_CTLCOLORSTATIC, sent|parent },
6625 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6626 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 },
6627 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO2 },
6628 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 },
6629 { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO1 },
6630 { WM_CTLCOLORSTATIC, sent|parent },
6631 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6632 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 },
6633 { BM_SETCHECK, sent|wparam|lparam|defwinproc, 0, ID_RADIO3 },
6634 { WM_CTLCOLORSTATIC, sent|parent },
6635 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6636 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 },
6637 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6638 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
6639 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO2, BN_CLICKED) },
6640 { WM_NCHITTEST, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6641 { WM_SETCURSOR, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6642 { WM_MOUSEMOVE, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6643 { 0 }
6644 };
6645
6646 static const struct message auto_radio_button_VK_UP_child[] =
6647 {
6648 { WM_KEYDOWN, sent|wparam|lparam, VK_UP, 0 },
6649 { WM_KEYUP, sent|wparam|lparam, VK_UP, 0 },
6650 { 0 }
6651 };
6652
6653 static const struct message auto_radio_button_VK_UP_parent[] =
6654 {
6655 { WM_KEYDOWN, sent|wparam|lparam|parent, VK_UP, 0 },
6656 { WM_KEYUP, sent|wparam|lparam|parent, VK_UP, 0 },
6657 { 0 }
6658 };
6659
6660 static const struct message auto_radio_button_VK_UP_dialog[] =
6661 {
6662 { WM_GETDLGCODE, sent|parent, 0, 0 },
6663
6664 /* optional trailer seen on some windows setups */
6665 { WM_CHANGEUISTATE, sent|optional },
6666 { WM_UPDATEUISTATE, sent|optional },
6667 { WM_UPDATEUISTATE, sent|optional },
6668 { WM_UPDATEUISTATE, sent|optional },
6669 { WM_UPDATEUISTATE, sent|optional },
6670 { WM_UPDATEUISTATE, sent|optional },
6671 { WM_UPDATEUISTATE, sent|optional },
6672 { WM_UPDATEUISTATE, sent|optional },
6673 { WM_UPDATEUISTATE, sent|optional },
6674 { WM_UPDATEUISTATE, sent|optional },
6675 { WM_UPDATEUISTATE, sent|optional },
6676 { WM_UPDATEUISTATE, sent|optional },
6677 { WM_UPDATEUISTATE, sent|optional },
6678 { WM_UPDATEUISTATE, sent|optional },
6679 { WM_UPDATEUISTATE, sent|optional },
6680 { WM_UPDATEUISTATE, sent|optional },
6681 { WM_UPDATEUISTATE, sent|optional },
6682 { WM_UPDATEUISTATE, sent|optional },
6683 { WM_UPDATEUISTATE, sent|optional },
6684 { WM_CTLCOLORSTATIC, sent|parent|optional },
6685 { WM_CTLCOLORSTATIC, sent|parent|optional },
6686 { WM_CTLCOLORSTATIC, sent|parent|optional },
6687 { WM_UPDATEUISTATE, sent|optional },
6688 { WM_CTLCOLORSTATIC, sent|parent|optional },
6689 { WM_CTLCOLORSTATIC, sent|parent|optional },
6690 { WM_UPDATEUISTATE, sent|optional },
6691 { WM_CTLCOLORBTN, sent|parent|optional },
6692 { WM_CTLCOLORBTN, sent|parent|optional },
6693 { WM_UPDATEUISTATE, sent|optional },
6694 { WM_CTLCOLORSTATIC, sent|parent|optional },
6695 { WM_CTLCOLORSTATIC, sent|parent|optional },
6696 { 0 }
6697 };
6698
6699 static const struct message auto_radio_button_VK_DOWN_dialog[] =
6700 {
6701 { WM_GETDLGCODE, sent|parent, 0, 0 },
6702 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) },
6703 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6704 { HCBT_SETFOCUS, hook },
6705 { WM_KILLFOCUS, sent, 0, 0 },
6706 { WM_CTLCOLORSTATIC, sent|parent },
6707 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO3, BN_KILLFOCUS) },
6708 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6709 { WM_SETFOCUS, sent, 0, 0 },
6710 { WM_CTLCOLORSTATIC, sent|parent },
6711 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_SETFOCUS) },
6712 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) },
6713 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6714 { WM_GETDLGCODE, sent|parent, 0, 0 },
6715 { DM_GETDEFID, sent|parent, 0, 0 },
6716 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
6717 { BM_CLICK, sent|wparam|lparam, 1, 0 },
6718 { WM_LBUTTONDOWN, sent|wparam|lparam|defwinproc, 0, 0 },
6719 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
6720 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 },
6721 { WM_CTLCOLORSTATIC, sent|parent },
6722 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6723 { WM_LBUTTONUP, sent|wparam|lparam|defwinproc, 0, 0 },
6724 { BM_SETSTATE, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO1 },
6725 { WM_CTLCOLORSTATIC, sent|parent },
6726 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6727 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO1, 0 },
6728 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_CHECKED, ID_RADIO1 },
6729 { WM_CTLCOLORSTATIC, sent|parent },
6730 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6731 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO3, 0 },
6732 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO3 },
6733 { WM_CTLCOLORSTATIC, sent|parent },
6734 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6735 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_TEXT, 0 },
6736 { WM_GETDLGCODE, sent|wparam|lparam|defwinproc, ID_RADIO2, 0 },
6737 { BM_SETCHECK, sent|wparam|lparam|defwinproc, BST_UNCHECKED, ID_RADIO2 },
6738 { WM_CTLCOLORSTATIC, sent|parent },
6739 { EVENT_OBJECT_STATECHANGE, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
6740 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
6741 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
6742 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_RADIO1, BN_CLICKED) },
6743 { WM_NCHITTEST, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6744 { WM_SETCURSOR, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6745 { WM_MOUSEMOVE, sent|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
6746 { WM_PAINT, sent },
6747 { WM_CTLCOLORSTATIC, sent|parent },
6748 { 0 }
6749 };
6750
6751 static const struct message auto_radio_button_VK_DOWN_radio3[] =
6752 {
6753 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
6754 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO2 },
6755 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO3 },
6756 { WM_GETDLGCODE, sent|parent, 0, 0 },
6757 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, MAKELPARAM(WM_KEYDOWN, VK_DOWN) },
6758 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6759 { WM_GETDLGCODE, sent|wparam|lparam, ID_RADIO1, 0 },
6760 { WM_GETDLGCODE, sent|wparam|lparam|parent, 0, 0 },
6761 { WM_USER, sent|parent, 0, 0 },
6762 { BM_GETCHECK, sent|wparam|lparam, 0, ID_RADIO1 },
6763 { 0 }
6764 };
6765
6766 static const struct message auto_radio_button_VK_UP_radio1[] =
6767 {
6768 { WM_GETDLGCODE, sent|parent, 0, 0 },
6769 { 0 }
6770 };
6771
6772 static INT_PTR WINAPI radio_test_dlg_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
6773 {
6774 ParentMsgCheckProcA(hwnd, msg, wp, lp);
6775 return 1;
6776 }
6777
6778 static void test_autoradio_BM_CLICK(void)
6779 {
6780 HWND parent, radio1, radio2, radio3;
6781 RECT rc;
6782 MSG msg;
6783 DWORD ret;
6784
6785 subclass_button();
6786
6787 parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_1", 0, radio_test_dlg_proc, 0);
6788 ok(parent != 0, "failed to create parent window\n");
6789
6790 radio1 = GetDlgItem(parent, ID_RADIO1);
6791 radio2 = GetDlgItem(parent, ID_RADIO2);
6792 radio3 = GetDlgItem(parent, ID_RADIO3);
6793
6794 /* this avoids focus messages in the generated sequence */
6795 SetFocus(radio2);
6796
6797 flush_events();
6798 flush_sequence();
6799
6800 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6801 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6802 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6803 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6804 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6805 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6806
6807 SendMessageA(radio1, BM_SETCHECK, BST_CHECKED, 0);
6808
6809 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6810 ok(ret == BST_CHECKED, "got %08x\n", ret);
6811 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6812 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6813 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6814 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6815
6816 SendMessageA(radio2, BM_SETCHECK, BST_CHECKED, 0);
6817
6818 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6819 ok(ret == BST_CHECKED, "got %08x\n", ret);
6820 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6821 ok(ret == BST_CHECKED, "got %08x\n", ret);
6822 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6823 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6824
6825 SendMessageA(radio3, BM_SETCHECK, BST_CHECKED, 0);
6826
6827 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6828 ok(ret == BST_CHECKED, "got %08x\n", ret);
6829 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6830 ok(ret == BST_CHECKED, "got %08x\n", ret);
6831 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6832 ok(ret == BST_CHECKED, "got %08x\n", ret);
6833
6834 GetWindowRect(radio2, &rc);
6835 SetCursorPos(rc.left+1, rc.top+1);
6836
6837 flush_events();
6838 flush_sequence();
6839
6840 log_all_parent_messages++;
6841
6842 SendMessageA(radio2, BM_CLICK, 0, 0);
6843 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6844 ok_sequence(auto_radio_button_BM_CLICK, "BM_CLICK on auto-radio button", FALSE);
6845
6846 log_all_parent_messages--;
6847
6848 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6849 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6850 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6851 ok(ret == BST_CHECKED, "got %08x\n", ret);
6852 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6853 ok(ret == BST_UNCHECKED, "got %08x\n", ret);
6854
6855 DestroyWindow(parent);
6856 }
6857
6858 #define test_radio(r1, s1, r2, s2, r3, s3) test_radio_dbg(r1, s1, r2, s2, r3, s3, __LINE__)
6859 static void test_radio_dbg(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3, int line)
6860 {
6861 DWORD ret;
6862
6863 ret = SendMessageA(radio1, BM_GETCHECK, 0, 0);
6864 ok_(__FILE__,line)(ret == state1 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
6865 ret = SendMessageA(radio2, BM_GETCHECK, 0, 0);
6866 ok_(__FILE__,line)(ret == state2 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
6867 ret = SendMessageA(radio3, BM_GETCHECK, 0, 0);
6868 ok_(__FILE__,line)(ret == state3 ? BST_CHECKED : BST_UNCHECKED, "got %08x\n", ret);
6869 }
6870
6871 static void set_radio(HWND radio1, int state1, HWND radio2, int state2, HWND radio3, int state3)
6872 {
6873 SendMessageA(radio1, BM_SETCHECK, state1 ? BST_CHECKED : BST_UNCHECKED, 0);
6874 SendMessageA(radio2, BM_SETCHECK, state2 ? BST_CHECKED : BST_UNCHECKED, 0);
6875 SendMessageA(radio3, BM_SETCHECK, state3 ? BST_CHECKED : BST_UNCHECKED, 0);
6876 }
6877
6878 static void test_autoradio_kbd_move(void)
6879 {
6880 HWND parent, radio1, radio2, radio3, hwnd;
6881 RECT rc;
6882 MSG msg;
6883 DWORD ret;
6884
6885 subclass_button();
6886
6887 parent = CreateDialogParamA(0, "AUTORADIO_TEST_DIALOG_2", 0, radio_test_dlg_proc, 0);
6888 ok(parent != 0, "failed to create parent window\n");
6889
6890 radio1 = GetDlgItem(parent, ID_RADIO1);
6891 radio2 = GetDlgItem(parent, ID_RADIO2);
6892 radio3 = GetDlgItem(parent, ID_RADIO3);
6893
6894 flush_events();
6895 flush_sequence();
6896
6897 test_radio(radio1, 0, radio2, 0, radio3, 0);
6898 set_radio(radio1, 1, radio2, 1, radio3, 1);
6899 test_radio(radio1, 1, radio2, 1, radio3, 1);
6900
6901 SetFocus(radio3);
6902
6903 flush_events();
6904 flush_sequence();
6905
6906 log_all_parent_messages++;
6907
6908 SendMessageA(radio3, WM_KEYDOWN, VK_UP, 0);
6909 SendMessageA(radio3, WM_KEYUP, VK_UP, 0);
6910 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6911 ok_sequence(auto_radio_button_VK_UP_child, "press/release VK_UP on auto-radio button", FALSE);
6912
6913 test_radio(radio1, 1, radio2, 1, radio3, 1);
6914
6915 flush_events();
6916 flush_sequence();
6917
6918 DefDlgProcA(parent, WM_KEYDOWN, VK_UP, 0);
6919 DefDlgProcA(parent, WM_KEYUP, VK_UP, 0);
6920 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6921 ok_sequence(auto_radio_button_VK_UP_parent, "press/release VK_UP on dialog", FALSE);
6922
6923 test_radio(radio1, 1, radio2, 1, radio3, 1);
6924
6925 SetFocus(radio3);
6926 GetWindowRect(radio3, &rc);
6927
6928 flush_events();
6929 flush_sequence();
6930
6931 msg.hwnd = parent;
6932 msg.message = WM_KEYDOWN;
6933 msg.wParam = VK_UP;
6934 msg.lParam = 0;
6935 msg.pt.x = rc.left + 1;
6936 msg.pt.y = rc.top + 1;
6937 ret = IsDialogMessageA(parent, &msg);
6938 ok(ret, "IsDialogMessage should return TRUE\n");
6939 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6940 if (0) /* actual message sequence is different on every run in some Windows setups */
6941 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #1", FALSE);
6942 /* what really matters is that nothing has changed */
6943 test_radio(radio1, 1, radio2, 1, radio3, 1);
6944
6945 set_radio(radio1, 0, radio2, 1, radio3, 1);
6946 test_radio(radio1, 0, radio2, 1, radio3, 1);
6947
6948 flush_events();
6949 flush_sequence();
6950
6951 ret = IsDialogMessageA(parent, &msg);
6952 ok(ret, "IsDialogMessage should return TRUE\n");
6953 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6954 if (0) /* actual message sequence is different on every run in some Windows setups */
6955 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #2", FALSE);
6956 /* what really matters is that nothing has changed */
6957 test_radio(radio1, 0, radio2, 1, radio3, 1);
6958
6959 /* switch from radio3 ro radio1 */
6960 SetFocus(radio3);
6961 GetWindowRect(radio3, &rc);
6962
6963 flush_events();
6964 flush_sequence();
6965
6966 msg.hwnd = parent;
6967 msg.message = WM_KEYDOWN;
6968 msg.wParam = VK_DOWN;
6969 msg.lParam = 0;
6970 msg.pt.x = rc.left + 1;
6971 msg.pt.y = rc.top + 1;
6972 ret = IsDialogMessageA(parent, &msg);
6973 ok(ret, "IsDialogMessage should return TRUE\n");
6974 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6975 ok_sequence(auto_radio_button_VK_DOWN_dialog, "IsDialogMessage(VK_DOWN)", TRUE);
6976
6977 test_radio(radio1, 1, radio2, 0, radio3, 0);
6978
6979 hwnd = GetFocus();
6980 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
6981 GetWindowRect(radio1, &rc);
6982
6983 msg.hwnd = parent;
6984 msg.message = WM_KEYDOWN;
6985 msg.wParam = VK_DOWN;
6986 msg.lParam = 0;
6987 msg.pt.x = rc.left + 1;
6988 msg.pt.y = rc.top + 1;
6989 ret = IsDialogMessageA(parent, &msg);
6990 ok(ret, "IsDialogMessage should return TRUE\n");
6991 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
6992 ok_sequence(auto_radio_button_VK_DOWN_radio3, "down to radio3", TRUE);
6993
6994 test_radio(radio1, 1, radio2, 0, radio3, 0);
6995
6996 hwnd = GetFocus();
6997 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
6998
6999 flush_events();
7000 flush_sequence();
7001
7002 msg.hwnd = parent;
7003 msg.message = WM_KEYDOWN;
7004 msg.wParam = VK_UP;
7005 msg.lParam = 0;
7006 msg.pt.x = rc.left + 1;
7007 msg.pt.y = rc.top + 1;
7008 ret = IsDialogMessageA(parent, &msg);
7009 ok(ret, "IsDialogMessage should return TRUE\n");
7010 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7011 ok_sequence(auto_radio_button_VK_UP_radio1, "up to radio1", TRUE);
7012
7013 test_radio(radio1, 1, radio2, 0, radio3, 0);
7014
7015 hwnd = GetFocus();
7016 ok(hwnd == radio1, "focus should be on radio1, not on %p\n", hwnd);
7017
7018 flush_events();
7019 flush_sequence();
7020
7021 msg.hwnd = parent;
7022 msg.message = WM_KEYDOWN;
7023 msg.wParam = VK_UP;
7024 msg.lParam = 0;
7025 msg.pt.x = rc.left + 1;
7026 msg.pt.y = rc.top + 1;
7027 ret = IsDialogMessageA(parent, &msg);
7028 ok(ret, "IsDialogMessage should return TRUE\n");
7029 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
7030 if (0) /* actual message sequence is different on every run in some Windows setups */
7031 ok_sequence(auto_radio_button_VK_UP_dialog, "IsDialogMessage(VK_UP) #3", FALSE);
7032 /* what really matters is that nothing has changed */
7033 test_radio(radio1, 1, radio2, 0, radio3, 0);
7034
7035 log_all_parent_messages--;
7036
7037 DestroyWindow(parent);
7038 }
7039
7040 /****************** static message test *************************/
7041 static const struct message WmSetFontStaticSeq2[] =
7042 {
7043 { WM_SETFONT, sent },
7044 { WM_PAINT, sent|defwinproc|optional },
7045 { WM_ERASEBKGND, sent|defwinproc|optional },
7046 { WM_CTLCOLORSTATIC, sent|defwinproc|optional },
7047 { 0 }
7048 };
7049
7050 static WNDPROC old_static_proc;
7051
7052 static LRESULT CALLBACK static_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7053 {
7054 static LONG defwndproc_counter = 0;
7055 LRESULT ret;
7056 struct recvd_message msg;
7057
7058 if (ignore_message( message )) return 0;
7059
7060 msg.hwnd = hwnd;
7061 msg.message = message;
7062 msg.flags = sent|wparam|lparam;
7063 if (defwndproc_counter) msg.flags |= defwinproc;
7064 msg.wParam = wParam;
7065 msg.lParam = lParam;
7066 msg.descr = "static";
7067 add_message(&msg);
7068
7069 defwndproc_counter++;
7070 ret = CallWindowProcA(old_static_proc, hwnd, message, wParam, lParam);
7071 defwndproc_counter--;
7072
7073 return ret;
7074 }
7075
7076 static void subclass_static(void)
7077 {
7078 WNDCLASSA cls;
7079
7080 if (!GetClassInfoA(0, "static", &cls)) assert(0);
7081
7082 old_static_proc = cls.lpfnWndProc;
7083
7084 cls.hInstance = GetModuleHandleA(NULL);
7085 cls.lpfnWndProc = static_hook_proc;
7086 cls.lpszClassName = "my_static_class";
7087 UnregisterClassA(cls.lpszClassName, cls.hInstance);
7088 if (!RegisterClassA(&cls)) assert(0);
7089 }
7090
7091 static void test_static_messages(void)
7092 {
7093 /* FIXME: make as comprehensive as the button message test */
7094 static const struct
7095 {
7096 DWORD style;
7097 DWORD dlg_code;
7098 const struct message *setfont;
7099 } static_ctrl[] = {
7100 { SS_LEFT, DLGC_STATIC,
7101 WmSetFontStaticSeq2 }
7102 };
7103 unsigned int i;
7104 HWND hwnd;
7105 DWORD dlg_code;
7106
7107 subclass_static();
7108
7109 for (i = 0; i < sizeof(static_ctrl)/sizeof(static_ctrl[0]); i++)
7110 {
7111 hwnd = CreateWindowExA(0, "my_static_class", "test", static_ctrl[i].style | WS_POPUP,
7112 0, 0, 50, 14, 0, 0, 0, NULL);
7113 ok(hwnd != 0, "Failed to create static window\n");
7114
7115 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
7116 ok(dlg_code == static_ctrl[i].dlg_code, "%u: wrong dlg_code %08x\n", i, dlg_code);
7117
7118 ShowWindow(hwnd, SW_SHOW);
7119 UpdateWindow(hwnd);
7120 SetFocus(0);
7121 flush_sequence();
7122
7123 trace("static style %08x\n", static_ctrl[i].style);
7124 SendMessageA(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE);
7125 ok_sequence(static_ctrl[i].setfont, "WM_SETFONT on a static", FALSE);
7126
7127 DestroyWindow(hwnd);
7128 }
7129 }
7130
7131 /****************** ComboBox message test *************************/
7132 #define ID_COMBOBOX 0x000f
7133
7134 static const struct message WmKeyDownComboSeq[] =
7135 {
7136 { WM_KEYDOWN, sent|wparam|lparam, VK_DOWN, 0 },
7137 { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(1000, LBN_SELCHANGE) },
7138 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDOK) },
7139 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_COMBOBOX, CBN_SELCHANGE) },
7140 { WM_CTLCOLOREDIT, sent|parent },
7141 { WM_KEYUP, sent|wparam|lparam, VK_DOWN, 0 },
7142 { 0 }
7143 };
7144
7145 static const struct message WmSetPosComboSeq[] =
7146 {
7147 { WM_WINDOWPOSCHANGING, sent },
7148 { WM_NCCALCSIZE, sent|wparam, TRUE },
7149 { WM_CHILDACTIVATE, sent },
7150 { WM_WINDOWPOSCHANGED, sent },
7151 { WM_MOVE, sent|defwinproc },
7152 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
7153 { WM_WINDOWPOSCHANGING, sent|defwinproc },
7154 { WM_NCCALCSIZE, sent|defwinproc|wparam, TRUE },
7155 { WM_WINDOWPOSCHANGED, sent|defwinproc },
7156 { WM_SIZE, sent|defwinproc|wparam, SIZE_RESTORED },
7157 { 0 }
7158 };
7159
7160 static const struct message WMSetFocusComboBoxSeq[] =
7161 {
7162 { WM_SETFOCUS, sent },
7163 { WM_KILLFOCUS, sent|parent },
7164 { WM_SETFOCUS, sent },
7165 { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
7166 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
7167 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7168 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7169 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
7170 { 0 }
7171 };
7172
7173 static const struct message SetFocusButtonSeq[] =
7174 {
7175 { WM_KILLFOCUS, sent },
7176 { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
7177 { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
7178 { WM_LBUTTONUP, sent|defwinproc },
7179 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
7180 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
7181 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7182 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7183 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
7184 { WM_CTLCOLORBTN, sent|parent },
7185 { 0 }
7186 };
7187
7188 static const struct message SetFocusComboBoxSeq[] =
7189 {
7190 { WM_CTLCOLORBTN, sent|parent },
7191 { WM_SETFOCUS, sent },
7192 { WM_KILLFOCUS, sent|defwinproc },
7193 { WM_SETFOCUS, sent },
7194 { WM_COMMAND, sent|defwinproc|wparam, MAKEWPARAM(1001, EN_SETFOCUS) },
7195 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, INT_MAX },
7196 { WM_CTLCOLOREDIT, sent|defwinproc|optional },/* Not sent on W2000, XP or Server 2003 */
7197 { WM_CTLCOLOREDIT, sent|parent|optional },/* Not sent on W2000, XP or Server 2003 */
7198 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SETFOCUS) },
7199 { 0 }
7200 };
7201
7202 static const struct message SetFocusButtonSeq2[] =
7203 {
7204 { WM_KILLFOCUS, sent },
7205 { CB_GETCOMBOBOXINFO, sent|optional },/* Windows 2000 */
7206 { 0x0167, sent|optional },/* Undocumented message. Sent on all versions except Windows 2000 */
7207 { WM_LBUTTONUP, sent|defwinproc },
7208 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_SELENDCANCEL) },
7209 { EM_SETSEL, sent|defwinproc|wparam|lparam, 0, 0 },
7210 { WM_CTLCOLOREDIT, sent|defwinproc },
7211 { WM_CTLCOLOREDIT, sent|parent },
7212 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_COMBOBOX, CBN_KILLFOCUS) },
7213 { WM_CTLCOLORBTN, sent|parent },
7214 { 0 }
7215 };
7216
7217 static WNDPROC old_combobox_proc, edit_window_proc;
7218
7219 static LRESULT CALLBACK combobox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7220 {
7221 static LONG defwndproc_counter = 0;
7222 LRESULT ret;
7223 struct recvd_message msg;
7224
7225 /* do not log painting messages */
7226 if (message != WM_PAINT &&
7227 message != WM_NCPAINT &&
7228 message != WM_SYNCPAINT &&
7229 message != WM_ERASEBKGND &&
7230 message != WM_NCHITTEST &&
7231 message != WM_GETTEXT &&
7232 !ignore_message( message ))
7233 {
7234 msg.hwnd = hwnd;
7235 msg.message = message;
7236 msg.flags = sent|wparam|lparam;
7237 if (defwndproc_counter) msg.flags |= defwinproc;
7238 msg.wParam = wParam;
7239 msg.lParam = lParam;
7240 msg.descr = "combo";
7241 add_message(&msg);
7242 }
7243
7244 defwndproc_counter++;
7245 ret = CallWindowProcA(edit_window_proc, hwnd, message, wParam, lParam);
7246 defwndproc_counter--;
7247
7248 return ret;
7249 }
7250
7251 static LRESULT CALLBACK combobox_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7252 {
7253 static LONG defwndproc_counter = 0;
7254 LRESULT ret;
7255 struct recvd_message msg;
7256
7257 /* do not log painting messages */
7258 if (message != WM_PAINT &&
7259 message != WM_NCPAINT &&
7260 message != WM_SYNCPAINT &&
7261 message != WM_ERASEBKGND &&
7262 message != WM_NCHITTEST &&
7263 message != WM_GETTEXT &&
7264 !ignore_message( message ))
7265 {
7266 msg.hwnd = hwnd;
7267 msg.message = message;
7268 msg.flags = sent|wparam|lparam;
7269 if (defwndproc_counter) msg.flags |= defwinproc;
7270 msg.wParam = wParam;
7271 msg.lParam = lParam;
7272 msg.descr = "combo";
7273 add_message(&msg);
7274 }
7275
7276 defwndproc_counter++;
7277 ret = CallWindowProcA(old_combobox_proc, hwnd, message, wParam, lParam);
7278 defwndproc_counter--;
7279
7280 return ret;
7281 }
7282
7283 static void subclass_combobox(void)
7284 {
7285 WNDCLASSA cls;
7286
7287 if (!GetClassInfoA(0, "ComboBox", &cls)) assert(0);
7288
7289 old_combobox_proc = cls.lpfnWndProc;
7290
7291 cls.hInstance = GetModuleHandleA(NULL);
7292 cls.lpfnWndProc = combobox_hook_proc;
7293 cls.lpszClassName = "my_combobox_class";
7294 UnregisterClassA(cls.lpszClassName, cls.hInstance);
7295 if (!RegisterClassA(&cls)) assert(0);
7296 }
7297
7298 static void test_combobox_messages(void)
7299 {
7300 HWND parent, combo, button, edit;
7301 LRESULT ret;
7302 BOOL (WINAPI *pGetComboBoxInfo)(HWND, PCOMBOBOXINFO);
7303 COMBOBOXINFO cbInfo;
7304 BOOL res;
7305
7306 subclass_combobox();
7307
7308 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7309 100, 100, 200, 200, 0, 0, 0, NULL);
7310 ok(parent != 0, "Failed to create parent window\n");
7311 flush_sequence();
7312
7313 combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
7314 0, 0, 100, 150, parent, (HMENU)ID_COMBOBOX, 0, NULL);
7315 ok(combo != 0, "Failed to create combobox window\n");
7316
7317 UpdateWindow(combo);
7318
7319 ret = SendMessageA(combo, WM_GETDLGCODE, 0, 0);
7320 ok(ret == (DLGC_WANTCHARS | DLGC_WANTARROWS), "wrong dlg_code %08lx\n", ret);
7321
7322 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 0");
7323 ok(ret == 0, "expected 0, got %ld\n", ret);
7324 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 1");
7325 ok(ret == 1, "expected 1, got %ld\n", ret);
7326 ret = SendMessageA(combo, CB_ADDSTRING, 0, (LPARAM)"item 2");
7327 ok(ret == 2, "expected 2, got %ld\n", ret);
7328
7329 SendMessageA(combo, CB_SETCURSEL, 0, 0);
7330 SetFocus(combo);
7331 flush_sequence();
7332
7333 log_all_parent_messages++;
7334 SendMessageA(combo, WM_KEYDOWN, VK_DOWN, 0);
7335 SendMessageA(combo, WM_KEYUP, VK_DOWN, 0);
7336 log_all_parent_messages--;
7337 ok_sequence(WmKeyDownComboSeq, "WM_KEYDOWN/VK_DOWN on a ComboBox", FALSE);
7338
7339 flush_sequence();
7340 SetWindowPos(combo, 0, 10, 10, 120, 130, SWP_NOZORDER);
7341 ok_sequence(WmSetPosComboSeq, "repositioning messages on a ComboBox", FALSE);
7342
7343 DestroyWindow(combo);
7344 DestroyWindow(parent);
7345
7346 /* Start again. Test combobox text selection when getting and losing focus */
7347 pGetComboBoxInfo = (void *)GetProcAddress(GetModuleHandleA("user32.dll"), "GetComboBoxInfo");
7348 if (!pGetComboBoxInfo)
7349 {
7350 win_skip("GetComboBoxInfo is not available\n");
7351 return;
7352 }
7353
7354 parent = CreateWindowExA(0, "TestParentClass", "Parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
7355 10, 10, 300, 300, NULL, NULL, NULL, NULL);
7356 ok(parent != 0, "Failed to create parent window\n");
7357
7358 combo = CreateWindowExA(0, "my_combobox_class", "test", WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
7359 5, 5, 100, 100, parent, (HMENU)ID_COMBOBOX, NULL, NULL);
7360 ok(combo != 0, "Failed to create combobox window\n");
7361
7362 cbInfo.cbSize = sizeof(COMBOBOXINFO);
7363 SetLastError(0xdeadbeef);
7364 res = pGetComboBoxInfo(combo, &cbInfo);
7365 ok(res, "Failed to get COMBOBOXINFO structure; LastError: %u\n", GetLastError());
7366 edit = cbInfo.hwndItem;
7367
7368 edit_window_proc = (WNDPROC)SetWindowLongPtrA(edit, GWLP_WNDPROC, (ULONG_PTR)combobox_subclass_proc);
7369
7370 button = CreateWindowExA(0, "Button", "OK", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
7371 5, 50, 100, 20, parent, NULL,
7372 (HINSTANCE)GetWindowLongPtrA(parent, GWLP_HINSTANCE), NULL);
7373 ok(button != 0, "Failed to create button window\n");
7374
7375 flush_sequence();
7376 log_all_parent_messages++;
7377 SendMessageA(combo, WM_SETFOCUS, 0, (LPARAM)edit);
7378 log_all_parent_messages--;
7379 ok_sequence(WMSetFocusComboBoxSeq, "WM_SETFOCUS on a ComboBox", TRUE);
7380
7381 flush_sequence();
7382 log_all_parent_messages++;
7383 SetFocus(button);
7384 log_all_parent_messages--;
7385 ok_sequence(SetFocusButtonSeq, "SetFocus on a Button", TRUE);
7386
7387 SendMessageA(combo, WM_SETTEXT, 0, (LPARAM)"Wine Test");
7388
7389 flush_sequence();
7390 log_all_parent_messages++;
7391 SetFocus(combo);
7392 log_all_parent_messages--;
7393 ok_sequence(SetFocusComboBoxSeq, "SetFocus on a ComboBox", TRUE);
7394
7395 flush_sequence();
7396 log_all_parent_messages++;
7397 SetFocus(button);
7398 log_all_parent_messages--;
7399 ok_sequence(SetFocusButtonSeq2, "SetFocus on a Button (2)", TRUE);
7400
7401 DestroyWindow(button);
7402 DestroyWindow(combo);
7403 DestroyWindow(parent);
7404 }
7405
7406 /****************** WM_IME_KEYDOWN message test *******************/
7407
7408 static const struct message WmImeKeydownMsgSeq_0[] =
7409 {
7410 { WM_IME_KEYDOWN, wparam, VK_RETURN },
7411 { WM_CHAR, wparam, 'A' },
7412 { 0 }
7413 };
7414
7415 static const struct message WmImeKeydownMsgSeq_1[] =
7416 {
7417 { WM_KEYDOWN, optional|wparam, VK_RETURN },
7418 { WM_CHAR, optional|wparam, VK_RETURN },
7419 { 0 }
7420 };
7421
7422 static LRESULT WINAPI wmime_keydown_procA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
7423 {
7424 struct recvd_message msg;
7425
7426 msg.hwnd = hwnd;
7427 msg.message = message;
7428 msg.flags = wparam|lparam;
7429 msg.wParam = wParam;
7430 msg.lParam = lParam;
7431 msg.descr = "wmime_keydown";
7432 add_message(&msg);
7433
7434 return DefWindowProcA(hwnd, message, wParam, lParam);
7435 }
7436
7437 static void register_wmime_keydown_class(void)
7438 {
7439 WNDCLASSA cls;
7440
7441 ZeroMemory(&cls, sizeof(WNDCLASSA));
7442 cls.lpfnWndProc = wmime_keydown_procA;
7443 cls.hInstance = GetModuleHandleA(0);
7444 cls.lpszClassName = "wmime_keydown_class";
7445 if (!RegisterClassA(&cls)) assert(0);
7446 }
7447
7448 static void test_wmime_keydown_message(void)
7449 {
7450 HWND hwnd;
7451 MSG msg;
7452
7453 trace("Message sequences by WM_IME_KEYDOWN\n");
7454
7455 register_wmime_keydown_class();
7456 hwnd = CreateWindowExA(0, "wmime_keydown_class", NULL, WS_OVERLAPPEDWINDOW,
7457 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
7458 NULL, NULL, 0);
7459 flush_events();
7460 flush_sequence();
7461
7462 SendMessageA(hwnd, WM_IME_KEYDOWN, VK_RETURN, 0x1c0001);
7463 SendMessageA(hwnd, WM_CHAR, 'A', 1);
7464 ok_sequence(WmImeKeydownMsgSeq_0, "WM_IME_KEYDOWN 0", FALSE);
7465
7466 while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
7467 {
7468 TranslateMessage(&msg);
7469 DispatchMessageA(&msg);
7470 }
7471 ok_sequence(WmImeKeydownMsgSeq_1, "WM_IME_KEYDOWN 1", FALSE);
7472
7473 DestroyWindow(hwnd);
7474 }
7475
7476 /************* painting message test ********************/
7477
7478 void dump_region(HRGN hrgn)
7479 {
7480 DWORD i, size;
7481 RGNDATA *data = NULL;
7482 RECT *rect;
7483
7484 if (!hrgn)
7485 {
7486 printf( "null region\n" );
7487 return;
7488 }
7489 if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
7490 if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
7491 GetRegionData( hrgn, size, data );
7492 printf("%d rects:", data->rdh.nCount );
7493 for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
7494 printf( " %s", wine_dbgstr_rect( rect ));
7495 printf("\n");
7496 HeapFree( GetProcessHeap(), 0, data );
7497 }
7498
7499 static void check_update_rgn( HWND hwnd, HRGN hrgn )
7500 {
7501 INT ret;
7502 RECT r1, r2;
7503 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
7504 HRGN update = CreateRectRgn( 0, 0, 0, 0 );
7505
7506 ret = GetUpdateRgn( hwnd, update, FALSE );
7507 ok( ret != ERROR, "GetUpdateRgn failed\n" );
7508 if (ret == NULLREGION)
7509 {
7510 ok( !hrgn, "Update region shouldn't be empty\n" );
7511 }
7512 else
7513 {
7514 if (CombineRgn( tmp, hrgn, update, RGN_XOR ) != NULLREGION)
7515 {
7516 ok( 0, "Regions are different\n" );
7517 if (winetest_debug > 0)
7518 {
7519 printf( "Update region: " );
7520 dump_region( update );
7521 printf( "Wanted region: " );
7522 dump_region( hrgn );
7523 }
7524 }
7525 }
7526 GetRgnBox( update, &r1 );
7527 GetUpdateRect( hwnd, &r2, FALSE );
7528 ok( EqualRect( &r1, &r2 ), "Rectangles are different: %s / %s\n", wine_dbgstr_rect( &r1 ),
7529 wine_dbgstr_rect( &r2 ));
7530
7531 DeleteObject( tmp );
7532 DeleteObject( update );
7533 }
7534
7535 static const struct message WmInvalidateRgn[] = {
7536 { WM_NCPAINT, sent },
7537 { WM_GETTEXT, sent|defwinproc|optional },
7538 { 0 }
7539 };
7540
7541 static const struct message WmGetUpdateRect[] = {
7542 { WM_NCPAINT, sent },
7543 { WM_GETTEXT, sent|defwinproc|optional },
7544 { WM_PAINT, sent },
7545 { 0 }
7546 };
7547
7548 static const struct message WmInvalidateFull[] = {
7549 { WM_NCPAINT, sent|wparam, 1 },
7550 { WM_GETTEXT, sent|defwinproc|optional },
7551 { 0 }
7552 };
7553
7554 static const struct message WmInvalidateErase[] = {
7555 { WM_NCPAINT, sent|wparam, 1 },
7556 { WM_GETTEXT, sent|defwinproc|optional },
7557 { WM_ERASEBKGND, sent },
7558 { 0 }
7559 };
7560
7561 static const struct message WmInvalidatePaint[] = {
7562 { WM_PAINT, sent },
7563 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
7564 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7565 { 0 }
7566 };
7567
7568 static const struct message WmInvalidateErasePaint[] = {
7569 { WM_PAINT, sent },
7570 { WM_NCPAINT, sent|wparam|beginpaint, 1 },
7571 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7572 { WM_ERASEBKGND, sent|beginpaint|optional },
7573 { 0 }
7574 };
7575
7576 static const struct message WmInvalidateErasePaint2[] = {
7577 { WM_PAINT, sent },
7578 { WM_NCPAINT, sent|beginpaint },
7579 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7580 { WM_ERASEBKGND, sent|beginpaint|optional },
7581 { 0 }
7582 };
7583
7584 static const struct message WmErase[] = {
7585 { WM_ERASEBKGND, sent },
7586 { 0 }
7587 };
7588
7589 static const struct message WmPaint[] = {
7590 { WM_PAINT, sent },
7591 { 0 }
7592 };
7593
7594 static const struct message WmParentOnlyPaint[] = {
7595 { WM_PAINT, sent|parent },
7596 { 0 }
7597 };
7598
7599 static const struct message WmInvalidateParent[] = {
7600 { WM_NCPAINT, sent|parent },
7601 { WM_GETTEXT, sent|defwinproc|parent|optional },
7602 { WM_ERASEBKGND, sent|parent },
7603 { 0 }
7604 };
7605
7606 static const struct message WmInvalidateParentChild[] = {
7607 { WM_NCPAINT, sent|parent },
7608 { WM_GETTEXT, sent|defwinproc|parent|optional },
7609 { WM_ERASEBKGND, sent|parent },
7610 { WM_NCPAINT, sent },
7611 { WM_GETTEXT, sent|defwinproc|optional },
7612 { WM_ERASEBKGND, sent },
7613 { 0 }
7614 };
7615
7616 static const struct message WmInvalidateParentChild2[] = {
7617 { WM_ERASEBKGND, sent|parent },
7618 { WM_NCPAINT, sent },
7619 { WM_GETTEXT, sent|defwinproc|optional },
7620 { WM_ERASEBKGND, sent },
7621 { 0 }
7622 };
7623
7624 static const struct message WmParentPaint[] = {
7625 { WM_PAINT, sent|parent },
7626 { WM_PAINT, sent },
7627 { 0 }
7628 };
7629
7630 static const struct message WmParentPaintNc[] = {
7631 { WM_PAINT, sent|parent },
7632 { WM_PAINT, sent },
7633 { WM_NCPAINT, sent|beginpaint },
7634 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7635 { WM_ERASEBKGND, sent|beginpaint|optional },
7636 { 0 }
7637 };
7638
7639 static const struct message WmChildPaintNc[] = {
7640 { WM_PAINT, sent },
7641 { WM_NCPAINT, sent|beginpaint },
7642 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7643 { WM_ERASEBKGND, sent|beginpaint|optional },
7644 { 0 }
7645 };
7646
7647 static const struct message WmParentErasePaint[] = {
7648 { WM_PAINT, sent|parent },
7649 { WM_NCPAINT, sent|parent|beginpaint },
7650 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
7651 { WM_ERASEBKGND, sent|parent|beginpaint|optional },
7652 { WM_PAINT, sent },
7653 { WM_NCPAINT, sent|beginpaint },
7654 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
7655 { WM_ERASEBKGND, sent|beginpaint|optional },
7656 { 0 }
7657 };
7658
7659 static const struct message WmParentOnlyNcPaint[] = {
7660 { WM_PAINT, sent|parent },
7661 { WM_NCPAINT, sent|parent|beginpaint },
7662 { WM_GETTEXT, sent|parent|beginpaint|defwinproc|optional },
7663 { 0 }
7664 };
7665
7666 static const struct message WmSetParentStyle[] = {
7667 { WM_STYLECHANGING, sent|parent },
7668 { WM_STYLECHANGED, sent|parent },
7669 { 0 }
7670 };
7671
7672 static void test_paint_messages(void)
7673 {
7674 BOOL ret;
7675 RECT rect, rect2;
7676 POINT pt;
7677 MSG msg;
7678 HWND hparent, hchild;
7679 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
7680 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
7681 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
7682 100, 100, 200, 200, 0, 0, 0, NULL);
7683 ok (hwnd != 0, "Failed to create overlapped window\n");
7684
7685 ShowWindow( hwnd, SW_SHOW );
7686 UpdateWindow( hwnd );
7687 flush_events();
7688 flush_sequence();
7689
7690 check_update_rgn( hwnd, 0 );
7691 SetRectRgn( hrgn, 10, 10, 20, 20 );
7692 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7693 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7694 check_update_rgn( hwnd, hrgn );
7695 SetRectRgn( hrgn2, 20, 20, 30, 30 );
7696 ret = RedrawWindow( hwnd, NULL, hrgn2, RDW_INVALIDATE );
7697 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7698 CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
7699 check_update_rgn( hwnd, hrgn );
7700 /* validate everything */
7701 ret = RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7702 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7703 check_update_rgn( hwnd, 0 );
7704
7705 /* test empty region */
7706 SetRectRgn( hrgn, 10, 10, 10, 15 );
7707 ret = RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7708 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7709 check_update_rgn( hwnd, 0 );
7710 /* test empty rect */
7711 SetRect( &rect, 10, 10, 10, 15 );
7712 ret = RedrawWindow( hwnd, &rect, NULL, RDW_INVALIDATE );
7713 ok(ret, "RedrawWindow returned %d instead of TRUE\n", ret);
7714 check_update_rgn( hwnd, 0 );
7715
7716 /* flush pending messages */
7717 flush_events();
7718 flush_sequence();
7719
7720 GetClientRect( hwnd, &rect );
7721 SetRectRgn( hrgn, 0, 0, rect.right - rect.left, rect.bottom - rect.top );
7722 /* MSDN: if hwnd parameter is NULL, InvalidateRect invalidates and redraws
7723 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
7724 */
7725 trace("testing InvalidateRect(0, NULL, FALSE)\n");
7726 SetRectEmpty( &rect );
7727 ok(InvalidateRect(0, &rect, FALSE), "InvalidateRect(0, &rc, FALSE) should fail\n");
7728 check_update_rgn( hwnd, hrgn );
7729 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7730 flush_events();
7731 ok_sequence( WmPaint, "Paint", FALSE );
7732 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7733 check_update_rgn( hwnd, 0 );
7734
7735 /* MSDN: if hwnd parameter is NULL, ValidateRect invalidates and redraws
7736 * all windows and sends WM_ERASEBKGND and WM_NCPAINT.
7737 */
7738 trace("testing ValidateRect(0, NULL)\n");
7739 SetRectEmpty( &rect );
7740 if (ValidateRect(0, &rect) && /* not supported on Win9x */
7741 GetUpdateRect(hwnd, NULL, FALSE)) /* or >= Win 8 */
7742 {
7743 check_update_rgn( hwnd, hrgn );
7744 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7745 flush_events();
7746 ok_sequence( WmPaint, "Paint", FALSE );
7747 RedrawWindow( hwnd, NULL, NULL, RDW_VALIDATE );
7748 check_update_rgn( hwnd, 0 );
7749 }
7750
7751 trace("testing InvalidateRgn(0, NULL, FALSE)\n");
7752 SetLastError(0xdeadbeef);
7753 ok(!InvalidateRgn(0, NULL, FALSE), "InvalidateRgn(0, NULL, FALSE) should fail\n");
7754 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || GetLastError() == 0xdeadbeef,
7755 "wrong error code %d\n", GetLastError());
7756 check_update_rgn( hwnd, 0 );
7757 flush_events();
7758 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7759
7760 trace("testing ValidateRgn(0, NULL)\n");
7761 SetLastError(0xdeadbeef);
7762 ok(!ValidateRgn(0, NULL), "ValidateRgn(0, NULL) should fail\n");
7763 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
7764 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
7765 "wrong error code %d\n", GetLastError());
7766 check_update_rgn( hwnd, 0 );
7767 flush_events();
7768 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7769
7770 trace("testing UpdateWindow(NULL)\n");
7771 SetLastError(0xdeadbeef);
7772 ok(!UpdateWindow(NULL), "UpdateWindow(NULL) should fail\n");
7773 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
7774 broken( GetLastError() == 0xdeadbeef ) /* win9x */,
7775 "wrong error code %d\n", GetLastError());
7776 check_update_rgn( hwnd, 0 );
7777 flush_events();
7778 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
7779
7780 /* now with frame */
7781 SetRectRgn( hrgn, -5, -5, 20, 20 );
7782
7783 /* flush pending messages */
7784 flush_events();
7785 flush_sequence();
7786 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7787 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
7788
7789 SetRectRgn( hrgn, 0, 0, 20, 20 ); /* GetUpdateRgn clips to client area */
7790 check_update_rgn( hwnd, hrgn );
7791
7792 flush_sequence();
7793 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
7794 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
7795
7796 flush_sequence();
7797 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW );
7798 ok_sequence( WmInvalidateFull, "InvalidateFull", FALSE );
7799
7800 GetClientRect( hwnd, &rect );
7801 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
7802 check_update_rgn( hwnd, hrgn );
7803
7804 flush_sequence();
7805 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW );
7806 ok_sequence( WmInvalidateErase, "InvalidateErase", FALSE );
7807
7808 flush_sequence();
7809 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASENOW | RDW_UPDATENOW );
7810 ok_sequence( WmInvalidatePaint, "InvalidatePaint", FALSE );
7811 check_update_rgn( hwnd, 0 );
7812
7813 flush_sequence();
7814 RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_UPDATENOW );
7815 ok_sequence( WmInvalidateErasePaint, "InvalidateErasePaint", FALSE );
7816 check_update_rgn( hwnd, 0 );
7817
7818 flush_sequence();
7819 SetRectRgn( hrgn, 0, 0, 100, 100 );
7820 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE );
7821 SetRectRgn( hrgn, 0, 0, 50, 100 );
7822 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE );
7823 SetRectRgn( hrgn, 50, 0, 100, 100 );
7824 check_update_rgn( hwnd, hrgn );
7825 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
7826 ok_sequence( WmEmptySeq, "EmptySeq", FALSE ); /* must not generate messages, everything is valid */
7827 check_update_rgn( hwnd, 0 );
7828
7829 flush_sequence();
7830 SetRectRgn( hrgn, 0, 0, 100, 100 );
7831 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
7832 SetRectRgn( hrgn, 0, 0, 100, 50 );
7833 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_ERASENOW );
7834 ok_sequence( WmErase, "Erase", FALSE );
7835 SetRectRgn( hrgn, 0, 50, 100, 100 );
7836 check_update_rgn( hwnd, hrgn );
7837
7838 flush_sequence();
7839 SetRectRgn( hrgn, 0, 0, 100, 100 );
7840 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE );
7841 SetRectRgn( hrgn, 0, 0, 50, 50 );
7842 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOERASE | RDW_UPDATENOW );
7843 ok_sequence( WmPaint, "Paint", FALSE );
7844
7845 flush_sequence();
7846 SetRectRgn( hrgn, -4, -4, -2, -2 );
7847 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7848 SetRectRgn( hrgn, -200, -200, -198, -198 );
7849 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME | RDW_ERASENOW );
7850 ok_sequence( WmEmptySeq, "EmptySeq", FALSE );
7851
7852 flush_sequence();
7853 SetRectRgn( hrgn, -4, -4, -2, -2 );
7854 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7855 SetRectRgn( hrgn, -4, -4, -3, -3 );
7856 RedrawWindow( hwnd, NULL, hrgn, RDW_VALIDATE | RDW_NOFRAME );
7857 SetRectRgn( hrgn, 0, 0, 1, 1 );
7858 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_UPDATENOW );
7859 ok_sequence( WmPaint, "Paint", FALSE );
7860
7861 flush_sequence();
7862 SetRectRgn( hrgn, -4, -4, -1, -1 );
7863 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7864 RedrawWindow( hwnd, NULL, 0, RDW_ERASENOW );
7865 /* make sure no WM_PAINT was generated */
7866 flush_events();
7867 ok_sequence( WmInvalidateRgn, "InvalidateRgn", FALSE );
7868
7869 flush_sequence();
7870 SetRectRgn( hrgn, -4, -4, -1, -1 );
7871 RedrawWindow( hwnd, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME );
7872 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
7873 {
7874 if (msg.hwnd == hwnd && msg.message == WM_PAINT)
7875 {
7876 /* GetUpdateRgn must return empty region since only nonclient area is invalidated */
7877 INT ret = GetUpdateRgn( hwnd, hrgn, FALSE );
7878 ok( ret == NULLREGION, "Invalid GetUpdateRgn result %d\n", ret );
7879 ret = GetUpdateRect( hwnd, &rect, FALSE );
7880 ok( ret, "Invalid GetUpdateRect result %d\n", ret );
7881 /* this will send WM_NCPAINT and validate the non client area */
7882 ret = GetUpdateRect( hwnd, &rect, TRUE );
7883 ok( !ret, "Invalid GetUpdateRect result %d\n", ret );
7884 }
7885 DispatchMessageA( &msg );
7886 }
7887 ok_sequence( WmGetUpdateRect, "GetUpdateRect", FALSE );
7888
7889 DestroyWindow( hwnd );
7890
7891 /* now test with a child window */
7892
7893 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW,
7894 100, 100, 200, 200, 0, 0, 0, NULL);
7895 ok (hparent != 0, "Failed to create parent window\n");
7896
7897 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE | WS_BORDER,
7898 10, 10, 100, 100, hparent, 0, 0, NULL);
7899 ok (hchild != 0, "Failed to create child window\n");
7900
7901 ShowWindow( hparent, SW_SHOW );
7902 UpdateWindow( hparent );
7903 UpdateWindow( hchild );
7904 flush_events();
7905 flush_sequence();
7906 log_all_parent_messages++;
7907
7908 SetRect( &rect, 0, 0, 50, 50 );
7909 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7910 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
7911 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild", FALSE );
7912
7913 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7914 pt.x = pt.y = 0;
7915 MapWindowPoints( hchild, hparent, &pt, 1 );
7916 SetRectRgn( hrgn, 0, 0, 50 - pt.x, 50 - pt.y );
7917 check_update_rgn( hchild, hrgn );
7918 SetRectRgn( hrgn, 0, 0, 50, 50 );
7919 check_update_rgn( hparent, hrgn );
7920 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
7921 ok_sequence( WmInvalidateParent, "InvalidateParent", FALSE );
7922 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
7923 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
7924
7925 flush_events();
7926 ok_sequence( WmParentPaintNc, "WmParentPaintNc", FALSE );
7927
7928 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
7929 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
7930 ok_sequence( WmInvalidateParent, "InvalidateParent2", FALSE );
7931 RedrawWindow( hchild, NULL, 0, RDW_ERASENOW );
7932 ok_sequence( WmEmptySeq, "EraseNow child", FALSE );
7933
7934 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
7935 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW | RDW_ALLCHILDREN );
7936 ok_sequence( WmInvalidateParentChild2, "InvalidateParentChild2", FALSE );
7937
7938 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
7939 flush_sequence();
7940 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
7941 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
7942 ok_sequence( WmInvalidateParentChild, "InvalidateParentChild3", FALSE );
7943
7944 /* flush all paint messages */
7945 flush_events();
7946 flush_sequence();
7947
7948 /* RDW_UPDATENOW on child with WS_CLIPCHILDREN doesn't change corresponding parent area */
7949 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
7950 SetRectRgn( hrgn, 0, 0, 50, 50 );
7951 check_update_rgn( hparent, hrgn );
7952 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
7953 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
7954 SetRectRgn( hrgn, 0, 0, 50, 50 );
7955 check_update_rgn( hparent, hrgn );
7956
7957 /* flush all paint messages */
7958 flush_events();
7959 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
7960 flush_sequence();
7961
7962 /* RDW_UPDATENOW on child without WS_CLIPCHILDREN will validate corresponding parent area */
7963 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7964 SetRectRgn( hrgn, 0, 0, 50, 50 );
7965 check_update_rgn( hparent, hrgn );
7966 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
7967 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
7968 SetRectRgn( hrgn2, 10, 10, 50, 50 );
7969 CombineRgn( hrgn, hrgn, hrgn2, RGN_DIFF );
7970 check_update_rgn( hparent, hrgn );
7971 /* flush all paint messages */
7972 flush_events();
7973 flush_sequence();
7974
7975 /* same as above but parent gets completely validated */
7976 SetRect( &rect, 20, 20, 30, 30 );
7977 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7978 SetRectRgn( hrgn, 20, 20, 30, 30 );
7979 check_update_rgn( hparent, hrgn );
7980 RedrawWindow( hchild, NULL, 0, RDW_UPDATENOW );
7981 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
7982 check_update_rgn( hparent, 0 ); /* no update region */
7983 flush_events();
7984 ok_sequence( WmEmptySeq, "WmEmpty", FALSE ); /* and no paint messages */
7985
7986 /* make sure RDW_VALIDATE on child doesn't have the same effect */
7987 flush_sequence();
7988 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7989 SetRectRgn( hrgn, 20, 20, 30, 30 );
7990 check_update_rgn( hparent, hrgn );
7991 RedrawWindow( hchild, NULL, 0, RDW_VALIDATE | RDW_NOERASE );
7992 SetRectRgn( hrgn, 20, 20, 30, 30 );
7993 check_update_rgn( hparent, hrgn );
7994
7995 /* same as above but normal WM_PAINT doesn't validate parent */
7996 flush_sequence();
7997 SetRect( &rect, 20, 20, 30, 30 );
7998 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
7999 SetRectRgn( hrgn, 20, 20, 30, 30 );
8000 check_update_rgn( hparent, hrgn );
8001 /* no WM_PAINT in child while parent still pending */
8002 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8003 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8004 while (PeekMessageA( &msg, hparent, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8005 ok_sequence( WmParentErasePaint, "WmParentErasePaint", FALSE );
8006
8007 flush_sequence();
8008 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8009 /* no WM_PAINT in child while parent still pending */
8010 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8011 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8012 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOCHILDREN );
8013 /* now that parent is valid child should get WM_PAINT */
8014 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8015 ok_sequence( WmInvalidateErasePaint2, "WmInvalidateErasePaint2", FALSE );
8016 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8017 ok_sequence( WmEmptySeq, "No other message", FALSE );
8018
8019 /* same thing with WS_CLIPCHILDREN in parent */
8020 flush_sequence();
8021 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) | WS_CLIPCHILDREN );
8022 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
8023 /* changing style invalidates non client area, but we need to invalidate something else to see it */
8024 RedrawWindow( hparent, &rect, 0, RDW_UPDATENOW );
8025 ok_sequence( WmEmptySeq, "No message", FALSE );
8026 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_UPDATENOW );
8027 ok_sequence( WmParentOnlyNcPaint, "WmParentOnlyNcPaint", FALSE );
8028
8029 flush_sequence();
8030 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
8031 SetRectRgn( hrgn, 20, 20, 30, 30 );
8032 check_update_rgn( hparent, hrgn );
8033 /* no WM_PAINT in child while parent still pending */
8034 while (PeekMessageA( &msg, hchild, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8035 ok_sequence( WmEmptySeq, "No WM_PAINT", FALSE );
8036 /* WM_PAINT in parent first */
8037 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
8038 ok_sequence( WmParentPaintNc, "WmParentPaintNc2", FALSE );
8039
8040 /* no RDW_ERASE in parent still causes RDW_ERASE and RDW_FRAME in child */
8041 flush_sequence();
8042 SetRect( &rect, 0, 0, 30, 30 );
8043 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN );
8044 SetRectRgn( hrgn, 0, 0, 30, 30 );
8045 check_update_rgn( hparent, hrgn );
8046 flush_events();
8047 ok_sequence( WmParentPaintNc, "WmParentPaintNc3", FALSE );
8048
8049 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
8050 flush_sequence();
8051 SetRect( &rect, -10, 0, 30, 30 );
8052 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
8053 SetRect( &rect, 0, 0, 20, 20 );
8054 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
8055 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
8056 ok_sequence( WmChildPaintNc, "WmChildPaintNc", FALSE );
8057
8058 /* validate doesn't cause RDW_NOERASE or RDW_NOFRAME in child */
8059 flush_sequence();
8060 SetRect( &rect, -10, 0, 30, 30 );
8061 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
8062 SetRect( &rect, 0, 0, 100, 100 );
8063 RedrawWindow( hparent, &rect, 0, RDW_VALIDATE | RDW_ALLCHILDREN );
8064 RedrawWindow( hparent, NULL, 0, RDW_UPDATENOW );
8065 ok_sequence( WmEmptySeq, "WmChildPaintNc2", FALSE );
8066 RedrawWindow( hparent, NULL, 0, RDW_ERASENOW );
8067 ok_sequence( WmEmptySeq, "WmChildPaintNc3", FALSE );
8068
8069 /* WS_CLIPCHILDREN doesn't exclude children from update region */
8070 flush_sequence();
8071 RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
8072 GetClientRect( hparent, &rect );
8073 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8074 check_update_rgn( hparent, hrgn );
8075 flush_events();
8076
8077 RedrawWindow( hparent, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
8078 GetClientRect( hparent, &rect );
8079 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8080 check_update_rgn( hparent, hrgn );
8081 flush_events();
8082
8083 /* test RDW_INTERNALPAINT behavior */
8084
8085 flush_sequence();
8086 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_NOCHILDREN );
8087 flush_events();
8088 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
8089
8090 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT | RDW_ALLCHILDREN );
8091 flush_events();
8092 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
8093
8094 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
8095 flush_events();
8096 ok_sequence( WmParentOnlyPaint, "WmParentOnlyPaint", FALSE );
8097
8098 assert( GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN );
8099 UpdateWindow( hparent );
8100 flush_events();
8101 flush_sequence();
8102 trace("testing SWP_FRAMECHANGED on parent with WS_CLIPCHILDREN\n");
8103 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8104 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
8105 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8106 flush_events();
8107 ok_sequence(WmSWP_FrameChanged_clip, "SetWindowPos:FrameChanged_clip", FALSE );
8108
8109 UpdateWindow( hparent );
8110 flush_events();
8111 flush_sequence();
8112 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent with WS_CLIPCHILDREN\n");
8113 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8114 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
8115 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8116 flush_events();
8117 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
8118
8119 SetWindowLongA( hparent, GWL_STYLE, GetWindowLongA(hparent,GWL_STYLE) & ~WS_CLIPCHILDREN );
8120 ok_sequence( WmSetParentStyle, "WmSetParentStyle", FALSE );
8121 RedrawWindow( hparent, NULL, 0, RDW_INTERNALPAINT );
8122 flush_events();
8123 ok_sequence( WmParentPaint, "WmParentPaint", FALSE );
8124
8125 assert( !(GetWindowLongA(hparent, GWL_STYLE) & WS_CLIPCHILDREN) );
8126 UpdateWindow( hparent );
8127 flush_events();
8128 flush_sequence();
8129 trace("testing SWP_FRAMECHANGED on parent without WS_CLIPCHILDREN\n");
8130 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8131 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
8132 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8133 flush_events();
8134 ok_sequence(WmSWP_FrameChanged_noclip, "SetWindowPos:FrameChanged_noclip", FALSE );
8135
8136 UpdateWindow( hparent );
8137 flush_events();
8138 flush_sequence();
8139 trace("testing SWP_FRAMECHANGED|SWP_DEFERERASE on parent without WS_CLIPCHILDREN\n");
8140 RedrawWindow( hchild, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
8141 SetWindowPos( hparent, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_DEFERERASE |
8142 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
8143 flush_events();
8144 ok_sequence(WmSWP_FrameChangedDeferErase, "SetWindowPos:FrameChangedDeferErase", FALSE );
8145
8146 ok(GetWindowLongA( hparent, GWL_STYLE ) & WS_VISIBLE, "parent should be visible\n");
8147 ok(GetWindowLongA( hchild, GWL_STYLE ) & WS_VISIBLE, "child should be visible\n");
8148
8149 UpdateWindow( hparent );
8150 flush_events();
8151 flush_sequence();
8152 trace("testing SetWindowPos(-10000, -10000) on child\n");
8153 SetWindowPos( hchild, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
8154 check_update_rgn( hchild, 0 );
8155 flush_events();
8156
8157 #if 0 /* this one doesn't pass under Wine yet */
8158 UpdateWindow( hparent );
8159 flush_events();
8160 flush_sequence();
8161 trace("testing ShowWindow(SW_MINIMIZE) on child\n");
8162 ShowWindow( hchild, SW_MINIMIZE );
8163 check_update_rgn( hchild, 0 );
8164 flush_events();
8165 #endif
8166
8167 UpdateWindow( hparent );
8168 flush_events();
8169 flush_sequence();
8170 trace("testing SetWindowPos(-10000, -10000) on parent\n");
8171 SetWindowPos( hparent, 0, -10000, -10000, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER );
8172 check_update_rgn( hparent, 0 );
8173 flush_events();
8174
8175 log_all_parent_messages--;
8176 DestroyWindow( hparent );
8177 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
8178
8179 /* tests for moving windows off-screen (needs simple WS_POPUP windows) */
8180
8181 hparent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_POPUP | WS_VISIBLE,
8182 100, 100, 200, 200, 0, 0, 0, NULL);
8183 ok (hparent != 0, "Failed to create parent window\n");
8184
8185 hchild = CreateWindowExA(0, "TestWindowClass", "Test child", WS_CHILD | WS_VISIBLE,
8186 10, 10, 100, 100, hparent, 0, 0, NULL);
8187 ok (hchild != 0, "Failed to create child window\n");
8188
8189 ShowWindow( hparent, SW_SHOW );
8190 UpdateWindow( hparent );
8191 UpdateWindow( hchild );
8192 flush_events();
8193 flush_sequence();
8194
8195 /* moving child outside of parent boundaries changes update region */
8196 SetRect( &rect, 0, 0, 40, 40 );
8197 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8198 SetRectRgn( hrgn, 0, 0, 40, 40 );
8199 check_update_rgn( hchild, hrgn );
8200 MoveWindow( hchild, -10, 10, 100, 100, FALSE );
8201 SetRectRgn( hrgn, 10, 0, 40, 40 );
8202 check_update_rgn( hchild, hrgn );
8203 MoveWindow( hchild, -10, -10, 100, 100, FALSE );
8204 SetRectRgn( hrgn, 10, 10, 40, 40 );
8205 check_update_rgn( hchild, hrgn );
8206
8207 /* moving parent off-screen does too */
8208 SetRect( &rect, 0, 0, 100, 100 );
8209 RedrawWindow( hparent, &rect, 0, RDW_INVALIDATE | RDW_ERASE | RDW_NOCHILDREN );
8210 SetRectRgn( hrgn, 0, 0, 100, 100 );
8211 check_update_rgn( hparent, hrgn );
8212 SetRectRgn( hrgn, 10, 10, 40, 40 );
8213 check_update_rgn( hchild, hrgn );
8214 MoveWindow( hparent, -20, -20, 200, 200, FALSE );
8215 GetUpdateRect( hparent, &rect2, FALSE );
8216 if (!EqualRect( &rect2, &rect )) /* Win 8 and later don't crop update to screen */
8217 {
8218 rect.left += 20;
8219 rect.top += 20;
8220 }
8221 SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
8222 check_update_rgn( hparent, hrgn );
8223 SetRectRgn( hrgn, rect.left + 10, rect.top + 10, 40, 40 );
8224 check_update_rgn( hchild, hrgn );
8225
8226 /* invalidated region is cropped by the parent rects */
8227 SetRect( &rect, 0, 0, 50, 50 );
8228 RedrawWindow( hchild, &rect, 0, RDW_INVALIDATE | RDW_ERASE );
8229 SetRectRgn( hrgn, rect2.left + 10, rect2.top + 10, 50, 50 );
8230 check_update_rgn( hchild, hrgn );
8231
8232 DestroyWindow( hparent );
8233 ok(!IsWindow(hchild), "child must be destroyed with its parent\n");
8234 flush_sequence();
8235
8236 DeleteObject( hrgn );
8237 DeleteObject( hrgn2 );
8238 }
8239
8240 struct wnd_event
8241 {
8242 HWND hwnd;
8243 HANDLE grand_child;
8244 HANDLE start_event;
8245 HANDLE stop_event;
8246 };
8247
8248 static DWORD WINAPI thread_proc(void *param)
8249 {
8250 MSG msg;
8251 struct wnd_event *wnd_event = param;
8252
8253 wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
8254 100, 100, 200, 200, 0, 0, 0, NULL);
8255 ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
8256
8257 SetEvent(wnd_event->start_event);
8258
8259 while (GetMessageA(&msg, 0, 0, 0))
8260 {
8261 TranslateMessage(&msg);
8262 DispatchMessageA(&msg);
8263 }
8264
8265 ok(IsWindow(wnd_event->hwnd), "window should still exist\n");
8266
8267 return 0;
8268 }
8269
8270 static DWORD CALLBACK create_grand_child_thread( void *param )
8271 {
8272 struct wnd_event *wnd_event = param;
8273 HWND hchild;
8274 MSG msg;
8275
8276 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
8277 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
8278 ok (hchild != 0, "Failed to create child window\n");
8279 flush_events();
8280 flush_sequence();
8281 SetEvent( wnd_event->start_event );
8282
8283 for (;;)
8284 {
8285 MsgWaitForMultipleObjects(0, NULL, FALSE, 1000, QS_ALLINPUT);
8286 if (!IsWindow( hchild )) break; /* will be destroyed when parent thread exits */
8287 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8288 }
8289 return 0;
8290 }
8291
8292 static DWORD CALLBACK create_child_thread( void *param )
8293 {
8294 struct wnd_event *wnd_event = param;
8295 struct wnd_event child_event;
8296 DWORD ret, tid;
8297 MSG msg;
8298
8299 child_event.hwnd = CreateWindowExA(0, "TestWindowClass", "Test child",
8300 WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, wnd_event->hwnd, 0, 0, NULL);
8301 ok (child_event.hwnd != 0, "Failed to create child window\n");
8302 SetFocus( child_event.hwnd );
8303 flush_events();
8304 flush_sequence();
8305 child_event.start_event = wnd_event->start_event;
8306 wnd_event->grand_child = CreateThread(NULL, 0, create_grand_child_thread, &child_event, 0, &tid);
8307 for (;;)
8308 {
8309 DWORD ret = MsgWaitForMultipleObjects(1, &child_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
8310 if (ret != 1) break;
8311 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8312 }
8313 ret = WaitForSingleObject( wnd_event->stop_event, 5000 );
8314 ok( !ret, "WaitForSingleObject failed %x\n", ret );
8315 return 0;
8316 }
8317
8318 static const char manifest_dep[] =
8319 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
8320 "<assemblyIdentity version=\"1.2.3.4\" name=\"testdep1\" type=\"win32\" processorArchitecture=\"" ARCH "\"/>"
8321 " <file name=\"testdep.dll\" />"
8322 "</assembly>";
8323
8324 static const char manifest_main[] =
8325 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
8326 "<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\" />"
8327 "<dependency>"
8328 " <dependentAssembly>"
8329 " <assemblyIdentity type=\"win32\" name=\"testdep1\" version=\"1.2.3.4\" processorArchitecture=\"" ARCH "\" />"
8330 " </dependentAssembly>"
8331 "</dependency>"
8332 "</assembly>";
8333
8334 static void create_manifest_file(const char *filename, const char *manifest)
8335 {
8336 WCHAR path[MAX_PATH];
8337 HANDLE file;
8338 DWORD size;
8339
8340 MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
8341 file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
8342 ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
8343 WriteFile(file, manifest, strlen(manifest), &size, NULL);
8344 CloseHandle(file);
8345 }
8346
8347 static HANDLE test_create(const char *file)
8348 {
8349 WCHAR path[MAX_PATH];
8350 ACTCTXW actctx;
8351 HANDLE handle;
8352
8353 MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH);
8354 memset(&actctx, 0, sizeof(ACTCTXW));
8355 actctx.cbSize = sizeof(ACTCTXW);
8356 actctx.lpSource = path;
8357
8358 handle = pCreateActCtxW(&actctx);
8359 ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError());
8360
8361 ok(actctx.cbSize == sizeof(actctx), "cbSize=%d\n", actctx.cbSize);
8362 ok(actctx.dwFlags == 0, "dwFlags=%d\n", actctx.dwFlags);
8363 ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource);
8364 ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
8365 ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId);
8366 ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
8367 ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName);
8368 ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName);
8369 ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule);
8370
8371 return handle;
8372 }
8373
8374 static void test_interthread_messages(void)
8375 {
8376 HANDLE hThread, context, handle, event;
8377 ULONG_PTR cookie;
8378 DWORD tid;
8379 WNDPROC proc;
8380 MSG msg;
8381 char buf[256];
8382 int len, expected_len;
8383 struct wnd_event wnd_event;
8384 BOOL ret;
8385
8386 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
8387 if (!wnd_event.start_event)
8388 {
8389 win_skip("skipping interthread message test under win9x\n");
8390 return;
8391 }
8392
8393 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
8394 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
8395
8396 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8397
8398 CloseHandle(wnd_event.start_event);
8399
8400 SetLastError(0xdeadbeef);
8401 ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeeded\n");
8402 ok(GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == 0xdeadbeef,
8403 "wrong error code %d\n", GetLastError());
8404
8405 proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
8406 ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %d\n", GetLastError());
8407
8408 expected_len = lstrlenA("window caption text");
8409 memset(buf, 0, sizeof(buf));
8410 SetLastError(0xdeadbeef);
8411 len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
8412 ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %d, len %d, expected len %d\n", GetLastError(), len, expected_len);
8413 ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
8414
8415 msg.hwnd = wnd_event.hwnd;
8416 msg.message = WM_GETTEXT;
8417 msg.wParam = sizeof(buf);
8418 msg.lParam = (LPARAM)buf;
8419 memset(buf, 0, sizeof(buf));
8420 SetLastError(0xdeadbeef);
8421 len = DispatchMessageA(&msg);
8422 ok((!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY) || broken(len), /* nt4 */
8423 "DispatchMessageA(WM_GETTEXT) succeeded on another thread window: ret %d, error %d\n", len, GetLastError());
8424
8425 /* the following test causes an exception in user.exe under win9x */
8426 msg.hwnd = wnd_event.hwnd;
8427 msg.message = WM_TIMER;
8428 msg.wParam = 0;
8429 msg.lParam = GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
8430 SetLastError(0xdeadbeef);
8431 len = DispatchMessageA(&msg);
8432 ok(!len && GetLastError() == 0xdeadbeef,
8433 "DispatchMessageA(WM_TIMER) failed on another thread window: ret %d, error %d\n", len, GetLastError());
8434
8435 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
8436 ok( ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
8437
8438 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8439 CloseHandle(hThread);
8440
8441 ok(!IsWindow(wnd_event.hwnd), "window should be destroyed on thread exit\n");
8442
8443 wnd_event.hwnd = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8444 100, 100, 200, 200, 0, 0, 0, NULL);
8445 ok (wnd_event.hwnd != 0, "Failed to create parent window\n");
8446 flush_events();
8447 flush_sequence();
8448 log_all_parent_messages++;
8449 wnd_event.start_event = CreateEventA( NULL, TRUE, FALSE, NULL );
8450 wnd_event.stop_event = CreateEventA( NULL, TRUE, FALSE, NULL );
8451 hThread = CreateThread( NULL, 0, create_child_thread, &wnd_event, 0, &tid );
8452 for (;;)
8453 {
8454 ret = MsgWaitForMultipleObjects(1, &wnd_event.start_event, FALSE, 1000, QS_SENDMESSAGE);
8455 if (ret != 1) break;
8456 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
8457 }
8458 ok( !ret, "MsgWaitForMultipleObjects failed %x\n", ret );
8459 /* now wait for the thread without processing messages; this shouldn't deadlock */
8460 SetEvent( wnd_event.stop_event );
8461 ret = WaitForSingleObject( hThread, 5000 );
8462 ok( !ret, "WaitForSingleObject failed %x\n", ret );
8463 CloseHandle( hThread );
8464
8465 ret = WaitForSingleObject( wnd_event.grand_child, 5000 );
8466 ok( !ret, "WaitForSingleObject failed %x\n", ret );
8467 CloseHandle( wnd_event.grand_child );
8468
8469 CloseHandle( wnd_event.start_event );
8470 CloseHandle( wnd_event.stop_event );
8471 flush_events();
8472 ok_sequence(WmExitThreadSeq, "destroy child on thread exit", FALSE);
8473 log_all_parent_messages--;
8474 DestroyWindow( wnd_event.hwnd );
8475
8476 /* activation context tests */
8477 if (!pActivateActCtx)
8478 {
8479 win_skip("Activation contexts are not supported, skipping\n");
8480 return;
8481 }
8482
8483 create_manifest_file("testdep1.manifest", manifest_dep);
8484 create_manifest_file("main.manifest", manifest_main);
8485
8486 context = test_create("main.manifest");
8487 DeleteFileA("testdep1.manifest");
8488 DeleteFileA("main.manifest");
8489
8490 handle = (void*)0xdeadbeef;
8491 ret = pGetCurrentActCtx(&handle);
8492 ok(ret, "GetCurrentActCtx failed: %u\n", GetLastError());
8493 ok(handle == 0, "active context %p\n", handle);
8494
8495 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
8496 hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
8497 ok(hThread != NULL, "CreateThread failed, error %d\n", GetLastError());
8498 ok(WaitForSingleObject(wnd_event.start_event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8499 CloseHandle(wnd_event.start_event);
8500
8501 /* context is activated after thread creation, so it doesn't inherit it by default */
8502 ret = pActivateActCtx(context, &cookie);
8503 ok(ret, "activation failed: %u\n", GetLastError());
8504
8505 handle = 0;
8506 ret = pGetCurrentActCtx(&handle);
8507 ok(ret, "GetCurrentActCtx failed: %u\n", GetLastError());
8508 ok(handle != 0, "active context %p\n", handle);
8509 pReleaseActCtx(handle);
8510
8511 /* destination window will test for active context */
8512 ret = SendMessageA(wnd_event.hwnd, WM_USER+10, 0, 0);
8513 ok(ret, "thread window returned %d\n", ret);
8514
8515 event = CreateEventW(NULL, 0, 0, NULL);
8516 ret = PostMessageA(wnd_event.hwnd, WM_USER+10, 0, (LPARAM)event);
8517 ok(ret, "thread window returned %d\n", ret);
8518 ok(WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8519 CloseHandle(event);
8520
8521 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
8522 ok(ret, "PostMessageA(WM_QUIT) error %d\n", GetLastError());
8523
8524 ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
8525 CloseHandle(hThread);
8526
8527 ret = pDeactivateActCtx(0, cookie);
8528 ok(ret, "DeactivateActCtx failed: %u\n", GetLastError());
8529 pReleaseActCtx(context);
8530 }
8531
8532
8533 static const struct message WmVkN[] = {
8534 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8535 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8536 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8537 { WM_CHAR, wparam|lparam, 'n', 1 },
8538 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1002,1), 0 },
8539 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8540 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8541 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8542 { 0 }
8543 };
8544 static const struct message WmShiftVkN[] = {
8545 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8546 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8547 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
8548 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8549 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8550 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8551 { WM_CHAR, wparam|lparam, 'N', 1 },
8552 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1001,1), 0 },
8553 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8554 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8555 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8556 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8557 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8558 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8559 { 0 }
8560 };
8561 static const struct message WmCtrlVkN[] = {
8562 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8563 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8564 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8565 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8566 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8567 { WM_KEYDOWN, sent|wparam|lparam, 'N', 1 },
8568 { WM_CHAR, wparam|lparam, 0x000e, 1 },
8569 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
8570 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8571 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8572 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8573 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8574 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8575 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8576 { 0 }
8577 };
8578 static const struct message WmCtrlVkN_2[] = {
8579 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8580 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8581 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8582 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8583 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8584 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1000,1), 0 },
8585 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8586 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8587 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8588 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8589 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8590 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8591 { 0 }
8592 };
8593 static const struct message WmAltVkN[] = {
8594 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8595 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8596 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8597 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8598 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
8599 { WM_SYSKEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
8600 { WM_SYSCHAR, wparam|lparam, 'n', 0x20000001 },
8601 { WM_SYSCHAR, sent|wparam|lparam, 'n', 0x20000001 },
8602 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 'n' },
8603 { HCBT_SYSCOMMAND, hook },
8604 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8605 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8606 { 0x00AE, sent|defwinproc|optional }, /* XP */
8607 { WM_GETTEXT, sent|defwinproc|optional }, /* XP */
8608 { WM_INITMENU, sent|defwinproc },
8609 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8610 { WM_MENUCHAR, sent|defwinproc|wparam, MAKEWPARAM('n',MF_SYSMENU) },
8611 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
8612 { WM_CAPTURECHANGED, sent|defwinproc },
8613 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,0xffff) },
8614 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8615 { WM_EXITMENULOOP, sent|defwinproc },
8616 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) }, /* Win95 bug */
8617 { WM_EXITMENULOOP, sent|defwinproc|optional }, /* Win95 bug */
8618 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8619 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
8620 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8621 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8622 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8623 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8624 { 0 }
8625 };
8626 static const struct message WmAltVkN_2[] = {
8627 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8628 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8629 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8630 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8631 { WM_SYSKEYDOWN, wparam|lparam, 'N', 0x20000001 },
8632 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1003,1), 0 },
8633 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8634 { WM_SYSKEYUP, wparam|lparam, 'N', 0xe0000001 },
8635 { WM_SYSKEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8636 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8637 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8638 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8639 { 0 }
8640 };
8641 static const struct message WmCtrlAltVkN[] = {
8642 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8643 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8644 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8645 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8646 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8647 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8648 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8649 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
8650 { WM_KEYDOWN, sent|wparam|lparam, 'N', 0x20000001 },
8651 { WM_CHAR, optional },
8652 { WM_CHAR, sent|optional },
8653 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8654 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
8655 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8656 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8657 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8658 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8659 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8660 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8661 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8662 { 0 }
8663 };
8664 static const struct message WmCtrlShiftVkN[] = {
8665 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8666 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8667 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8668 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8669 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8670 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
8671 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
8672 { WM_KEYDOWN, wparam|lparam, 'N', 1 },
8673 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1004,1), 0 },
8674 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
8675 { WM_KEYUP, wparam|lparam, 'N', 0xc0000001 },
8676 { WM_KEYUP, sent|wparam|lparam, 'N', 0xc0000001 },
8677 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8678 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8679 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8680 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8681 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8682 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8683 { 0 }
8684 };
8685 static const struct message WmCtrlAltShiftVkN[] = {
8686 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 1 }, /* XP */
8687 { WM_KEYDOWN, wparam|lparam, VK_CONTROL, 1 },
8688 { WM_KEYDOWN, sent|wparam|lparam, VK_CONTROL, 1 },
8689 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8690 { WM_KEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8691 { WM_KEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8692 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0x20000001 }, /* XP */
8693 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0x20000001 },
8694 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x20000001 },
8695 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x20000001 }, /* XP */
8696 { WM_KEYDOWN, wparam|lparam, 'N', 0x20000001 },
8697 { WM_COMMAND, sent|wparam|lparam, MAKEWPARAM(1005,1), 0 },
8698 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xe0000001 }, /* XP */
8699 { WM_KEYUP, wparam|lparam, 'N', 0xe0000001 },
8700 { WM_KEYUP, sent|wparam|lparam, 'N', 0xe0000001 },
8701 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xe0000001 }, /* XP */
8702 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xe0000001 },
8703 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xe0000001 },
8704 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8705 { WM_KEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8706 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8707 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_CONTROL, 0xc0000001 }, /* XP */
8708 { WM_KEYUP, wparam|lparam, VK_CONTROL, 0xc0000001 },
8709 { WM_KEYUP, sent|wparam|lparam, VK_CONTROL, 0xc0000001 },
8710 { 0 }
8711 };
8712 static const struct message WmAltPressRelease[] = {
8713 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 }, /* XP */
8714 { WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0x20000001 },
8715 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
8716 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8717 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8718 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8719 { WM_SYSCOMMAND, sent|defwinproc|wparam|lparam, SC_KEYMENU, 0 },
8720 { HCBT_SYSCOMMAND, hook },
8721 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8722 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8723 { WM_INITMENU, sent|defwinproc },
8724 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8725 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
8726 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8727
8728 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x30000001 }, /* XP */
8729
8730 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8731 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
8732 { WM_CAPTURECHANGED, sent|defwinproc },
8733 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
8734 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8735 { WM_EXITMENULOOP, sent|defwinproc },
8736 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 }, /* XP */
8737 { WM_SYSKEYUP, wparam|lparam, VK_MENU, 0xc0000001 },
8738 { WM_SYSKEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
8739 { 0 }
8740 };
8741 static const struct message WmShiftMouseButton[] = {
8742 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8743 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8744 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 1 },
8745 { WM_MOUSEMOVE, wparam|optional, 0, 0 },
8746 { WM_MOUSEMOVE, sent|wparam|optional, 0, 0 },
8747 { WM_LBUTTONDOWN, wparam, MK_LBUTTON|MK_SHIFT, 0 },
8748 { WM_LBUTTONDOWN, sent|wparam, MK_LBUTTON|MK_SHIFT, 0 },
8749 { WM_LBUTTONUP, wparam, MK_SHIFT, 0 },
8750 { WM_LBUTTONUP, sent|wparam, MK_SHIFT, 0 },
8751 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xc0000001 }, /* XP */
8752 { WM_KEYUP, wparam|lparam, VK_SHIFT, 0xc0000001 },
8753 { WM_KEYUP, sent|wparam|lparam, VK_SHIFT, 0xc0000001 },
8754 { 0 }
8755 };
8756 static const struct message WmF1Seq[] = {
8757 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 1 }, /* XP */
8758 { WM_KEYDOWN, wparam|lparam, VK_F1, 1 },
8759 { WM_KEYDOWN, sent|wparam|lparam, VK_F1, 0x00000001 },
8760 { WM_KEYF1, wparam|lparam, 0, 0 },
8761 { WM_KEYF1, sent|wparam|lparam, 0, 0 },
8762 { WM_HELP, sent|defwinproc },
8763 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F1, 0xc0000001 }, /* XP */
8764 { WM_KEYUP, wparam|lparam, VK_F1, 0xc0000001 },
8765 { WM_KEYUP, sent|wparam|lparam, VK_F1, 0xc0000001 },
8766 { 0 }
8767 };
8768 static const struct message WmVkAppsSeq[] = {
8769 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 1 }, /* XP */
8770 { WM_KEYDOWN, wparam|lparam, VK_APPS, 1 },
8771 { WM_KEYDOWN, sent|wparam|lparam, VK_APPS, 0x00000001 },
8772 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_APPS, 0xc0000001 }, /* XP */
8773 { WM_KEYUP, wparam|lparam, VK_APPS, 0xc0000001 },
8774 { WM_KEYUP, sent|wparam|lparam, VK_APPS, 0xc0000001 },
8775 { WM_CONTEXTMENU, lparam, /*hwnd*/0, -1 },
8776 { WM_CONTEXTMENU, sent|lparam, /*hwnd*/0, -1 },
8777 { 0 }
8778 };
8779 static const struct message WmVkF10Seq[] = {
8780 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
8781 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
8782 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
8783 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
8784 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
8785 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
8786 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
8787 { HCBT_SYSCOMMAND, hook },
8788 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8789 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
8790 { WM_INITMENU, sent|defwinproc },
8791 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8792 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
8793 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
8794
8795 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0x10000001 }, /* XP */
8796
8797 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
8798 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8799 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0, },
8800 { WM_CAPTURECHANGED, sent|defwinproc },
8801 { WM_MENUSELECT, sent|defwinproc|wparam|optional, MAKEWPARAM(0,0xffff) },
8802 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_SYSMENU, 0 },
8803 { WM_EXITMENULOOP, sent|defwinproc },
8804 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
8805 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
8806 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
8807 { 0 }
8808 };
8809 static const struct message WmShiftF10Seq[] = {
8810 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 1 }, /* XP */
8811 { WM_KEYDOWN, wparam|lparam, VK_SHIFT, 1 },
8812 { WM_KEYDOWN, sent|wparam|lparam, VK_SHIFT, 0x00000001 },
8813 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 1 }, /* XP */
8814 { WM_SYSKEYDOWN, wparam|lparam, VK_F10, 1 },
8815 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_F10, 0x00000001 },
8816 { WM_CONTEXTMENU, sent|defwinproc|lparam, /*hwnd*/0, -1 },
8817 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_F10, 0xc0000001 }, /* XP */
8818 { WM_SYSKEYUP, wparam|lparam, VK_F10, 0xc0000001 },
8819 { WM_SYSKEYUP, sent|wparam|lparam, VK_F10, 0xc0000001 },
8820 { WM_SYSCOMMAND, sent|defwinproc|wparam, SC_KEYMENU },
8821 { HCBT_SYSCOMMAND, hook },
8822 { WM_ENTERMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8823 { WM_INITMENU, sent|defwinproc },
8824 { WM_MENUSELECT, sent|defwinproc|wparam, MAKEWPARAM(0,MF_SYSMENU|MF_POPUP|MF_HILITE), 0, MAKEWPARAM(0,MF_RIGHTJUSTIFY) },
8825 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_SHIFT, 0xd0000001 }, /* XP */
8826 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0x10000001 }, /* XP */
8827 { WM_CAPTURECHANGED, sent|defwinproc|wparam|lparam, 0, 0 },
8828 { WM_MENUSELECT, sent|defwinproc|wparam|lparam, 0xffff0000, 0 },
8829 { WM_EXITMENULOOP, sent|defwinproc|wparam|lparam, 0, 0 },
8830 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 }, /* XP */
8831 { WM_KEYUP, wparam|lparam, VK_ESCAPE, 0xc0000001 },
8832 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
8833 { 0 }
8834 };
8835
8836 static void pump_msg_loop(HWND hwnd, HACCEL hAccel)
8837 {
8838 MSG msg;
8839
8840 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
8841 {
8842 struct recvd_message log_msg;
8843
8844 /* ignore some unwanted messages */
8845 if (msg.message == WM_MOUSEMOVE ||
8846 msg.message == WM_TIMER ||
8847 ignore_message( msg.message ))
8848 continue;
8849
8850 log_msg.hwnd = msg.hwnd;
8851 log_msg.message = msg.message;
8852 log_msg.flags = wparam|lparam;
8853 log_msg.wParam = msg.wParam;
8854 log_msg.lParam = msg.lParam;
8855 log_msg.descr = "accel";
8856 add_message(&log_msg);
8857
8858 if (!hAccel || !TranslateAcceleratorA(hwnd, hAccel, &msg))
8859 {
8860 TranslateMessage(&msg);
8861 DispatchMessageA(&msg);
8862 }
8863 }
8864 }
8865
8866 static void test_accelerators(void)
8867 {
8868 RECT rc;
8869 POINT pt;
8870 SHORT state;
8871 HACCEL hAccel;
8872 HWND hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
8873 100, 100, 200, 200, 0, 0, 0, NULL);
8874 BOOL ret;
8875
8876 assert(hwnd != 0);
8877 UpdateWindow(hwnd);
8878 flush_events();
8879 flush_sequence();
8880
8881 SetFocus(hwnd);
8882 ok(GetFocus() == hwnd, "wrong focus window %p\n", GetFocus());
8883
8884 state = GetKeyState(VK_SHIFT);
8885 ok(!(state & 0x8000), "wrong Shift state %04x\n", state);
8886 state = GetKeyState(VK_CAPITAL);
8887 ok(state == 0, "wrong CapsLock state %04x\n", state);
8888
8889 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
8890 assert(hAccel != 0);
8891
8892 flush_events();
8893 pump_msg_loop(hwnd, 0);
8894 flush_sequence();
8895
8896 trace("testing VK_N press/release\n");
8897 flush_sequence();
8898 keybd_event('N', 0, 0, 0);
8899 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8900 pump_msg_loop(hwnd, hAccel);
8901 if (!sequence_cnt) /* we didn't get any message */
8902 {
8903 skip( "queuing key events not supported\n" );
8904 goto done;
8905 }
8906 ok_sequence(WmVkN, "VK_N press/release", FALSE);
8907
8908 trace("testing Shift+VK_N press/release\n");
8909 flush_sequence();
8910 keybd_event(VK_SHIFT, 0, 0, 0);
8911 keybd_event('N', 0, 0, 0);
8912 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8913 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
8914 pump_msg_loop(hwnd, hAccel);
8915 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
8916
8917 trace("testing Ctrl+VK_N press/release\n");
8918 flush_sequence();
8919 keybd_event(VK_CONTROL, 0, 0, 0);
8920 keybd_event('N', 0, 0, 0);
8921 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8922 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
8923 pump_msg_loop(hwnd, hAccel);
8924 ok_sequence(WmCtrlVkN, "Ctrl+VK_N press/release", FALSE);
8925
8926 trace("testing Alt+VK_N press/release\n");
8927 flush_sequence();
8928 keybd_event(VK_MENU, 0, 0, 0);
8929 keybd_event('N', 0, 0, 0);
8930 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8931 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
8932 pump_msg_loop(hwnd, hAccel);
8933 ok_sequence(WmAltVkN, "Alt+VK_N press/release", FALSE);
8934
8935 trace("testing Ctrl+Alt+VK_N press/release 1\n");
8936 flush_sequence();
8937 keybd_event(VK_CONTROL, 0, 0, 0);
8938 keybd_event(VK_MENU, 0, 0, 0);
8939 keybd_event('N', 0, 0, 0);
8940 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8941 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
8942 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
8943 pump_msg_loop(hwnd, hAccel);
8944 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 1", FALSE);
8945
8946 ret = DestroyAcceleratorTable(hAccel);
8947 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
8948
8949 hAccel = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(2));
8950 assert(hAccel != 0);
8951
8952 trace("testing VK_N press/release\n");
8953 flush_sequence();
8954 keybd_event('N', 0, 0, 0);
8955 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8956 pump_msg_loop(hwnd, hAccel);
8957 ok_sequence(WmVkN, "VK_N press/release", FALSE);
8958
8959 trace("testing Shift+VK_N press/release\n");
8960 flush_sequence();
8961 keybd_event(VK_SHIFT, 0, 0, 0);
8962 keybd_event('N', 0, 0, 0);
8963 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8964 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
8965 pump_msg_loop(hwnd, hAccel);
8966 ok_sequence(WmShiftVkN, "Shift+VK_N press/release", FALSE);
8967
8968 trace("testing Ctrl+VK_N press/release 2\n");
8969 flush_sequence();
8970 keybd_event(VK_CONTROL, 0, 0, 0);
8971 keybd_event('N', 0, 0, 0);
8972 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8973 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
8974 pump_msg_loop(hwnd, hAccel);
8975 ok_sequence(WmCtrlVkN_2, "Ctrl+VK_N press/release 2", FALSE);
8976
8977 trace("testing Alt+VK_N press/release 2\n");
8978 flush_sequence();
8979 keybd_event(VK_MENU, 0, 0, 0);
8980 keybd_event('N', 0, 0, 0);
8981 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8982 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
8983 pump_msg_loop(hwnd, hAccel);
8984 ok_sequence(WmAltVkN_2, "Alt+VK_N press/release 2", FALSE);
8985
8986 trace("testing Ctrl+Alt+VK_N press/release 2\n");
8987 flush_sequence();
8988 keybd_event(VK_CONTROL, 0, 0, 0);
8989 keybd_event(VK_MENU, 0, 0, 0);
8990 keybd_event('N', 0, 0, 0);
8991 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
8992 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
8993 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
8994 pump_msg_loop(hwnd, hAccel);
8995 ok_sequence(WmCtrlAltVkN, "Ctrl+Alt+VK_N press/release 2", FALSE);
8996
8997 trace("testing Ctrl+Shift+VK_N press/release\n");
8998 flush_sequence();
8999 keybd_event(VK_CONTROL, 0, 0, 0);
9000 keybd_event(VK_SHIFT, 0, 0, 0);
9001 keybd_event('N', 0, 0, 0);
9002 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9003 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9004 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9005 pump_msg_loop(hwnd, hAccel);
9006 ok_sequence(WmCtrlShiftVkN, "Ctrl+Shift+VK_N press/release", FALSE);
9007
9008 trace("testing Ctrl+Alt+Shift+VK_N press/release\n");
9009 flush_sequence();
9010 keybd_event(VK_CONTROL, 0, 0, 0);
9011 keybd_event(VK_MENU, 0, 0, 0);
9012 keybd_event(VK_SHIFT, 0, 0, 0);
9013 keybd_event('N', 0, 0, 0);
9014 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
9015 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9016 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9017 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
9018 pump_msg_loop(hwnd, hAccel);
9019 ok_sequence(WmCtrlAltShiftVkN, "Ctrl+Alt+Shift+VK_N press/release", FALSE);
9020
9021 ret = DestroyAcceleratorTable(hAccel);
9022 ok( ret, "DestroyAcceleratorTable error %d\n", GetLastError());
9023 hAccel = 0;
9024
9025 trace("testing Alt press/release\n");
9026 flush_sequence();
9027 keybd_event(VK_MENU, 0, 0, 0);
9028 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9029 keybd_event(VK_MENU, 0, 0, 0);
9030 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
9031 pump_msg_loop(hwnd, 0);
9032 ok_sequence(WmAltPressRelease, "Alt press/release", FALSE);
9033
9034 trace("testing VK_F1 press/release\n");
9035 keybd_event(VK_F1, 0, 0, 0);
9036 keybd_event(VK_F1, 0, KEYEVENTF_KEYUP, 0);
9037 pump_msg_loop(hwnd, 0);
9038 ok_sequence(WmF1Seq, "F1 press/release", FALSE);
9039
9040 trace("testing VK_APPS press/release\n");
9041 keybd_event(VK_APPS, 0, 0, 0);
9042 keybd_event(VK_APPS, 0, KEYEVENTF_KEYUP, 0);
9043 pump_msg_loop(hwnd, 0);
9044 ok_sequence(WmVkAppsSeq, "VK_APPS press/release", FALSE);
9045
9046 trace("testing VK_F10 press/release\n");
9047 keybd_event(VK_F10, 0, 0, 0);
9048 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9049 keybd_event(VK_F10, 0, 0, 0);
9050 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9051 pump_msg_loop(hwnd, 0);
9052 ok_sequence(WmVkF10Seq, "VK_F10 press/release", FALSE);
9053
9054 trace("testing SHIFT+F10 press/release\n");
9055 keybd_event(VK_SHIFT, 0, 0, 0);
9056 keybd_event(VK_F10, 0, 0, 0);
9057 keybd_event(VK_F10, 0, KEYEVENTF_KEYUP, 0);
9058 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9059 keybd_event(VK_ESCAPE, 0, 0, 0);
9060 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
9061 pump_msg_loop(hwnd, 0);
9062 ok_sequence(WmShiftF10Seq, "SHIFT+F10 press/release", TRUE);
9063
9064 trace("testing Shift+MouseButton press/release\n");
9065 /* first, move mouse pointer inside of the window client area */
9066 GetClientRect(hwnd, &rc);
9067 MapWindowPoints(hwnd, 0, (LPPOINT)&rc, 2);
9068 rc.left += (rc.right - rc.left)/2;
9069 rc.top += (rc.bottom - rc.top)/2;
9070 SetCursorPos(rc.left, rc.top);
9071 SetActiveWindow(hwnd);
9072
9073 flush_events();
9074 flush_sequence();
9075 GetCursorPos(&pt);
9076 if (pt.x == rc.left && pt.y == rc.top)
9077 {
9078 int i;
9079 keybd_event(VK_SHIFT, 0, 0, 0);
9080 mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
9081 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
9082 keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
9083 pump_msg_loop(hwnd, 0);
9084 for (i = 0; i < sequence_cnt; i++) if (sequence[i].message == WM_LBUTTONDOWN) break;
9085 if (i < sequence_cnt)
9086 ok_sequence(WmShiftMouseButton, "Shift+MouseButton press/release", FALSE);
9087 else
9088 skip( "Shift+MouseButton event didn't get to the window\n" );
9089 }
9090
9091 done:
9092 if (hAccel) DestroyAcceleratorTable(hAccel);
9093 DestroyWindow(hwnd);
9094 }
9095
9096 /************* window procedures ********************/
9097
9098 static LRESULT MsgCheckProc (BOOL unicode, HWND hwnd, UINT message,
9099 WPARAM wParam, LPARAM lParam)
9100 {
9101 static LONG defwndproc_counter = 0;
9102 static LONG beginpaint_counter = 0;
9103 LRESULT ret;
9104 struct recvd_message msg;
9105
9106 if (ignore_message( message )) return 0;
9107
9108 switch (message)
9109 {
9110 case WM_ENABLE:
9111 {
9112 LONG style = GetWindowLongA(hwnd, GWL_STYLE);
9113 ok((BOOL)wParam == !(style & WS_DISABLED),
9114 "wrong WS_DISABLED state: %ld != %d\n", wParam, !(style & WS_DISABLED));
9115 break;
9116 }
9117
9118 case WM_CAPTURECHANGED:
9119 if (test_DestroyWindow_flag)
9120 {
9121 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
9122 if (style & WS_CHILD)
9123 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
9124 else if (style & WS_POPUP)
9125 lParam = WND_POPUP_ID;
9126 else
9127 lParam = WND_PARENT_ID;
9128 }
9129 break;
9130
9131 case WM_NCDESTROY:
9132 {
9133 HWND capture;
9134
9135 ok(!GetWindow(hwnd, GW_CHILD), "children should be unlinked at this point\n");
9136 capture = GetCapture();
9137 if (capture)
9138 {
9139 ok(capture == hwnd, "capture should NOT be released at this point (capture %p)\n", capture);
9140 trace("current capture %p, releasing...\n", capture);
9141 ReleaseCapture();
9142 }
9143 }
9144 /* fall through */
9145 case WM_DESTROY:
9146 if (pGetAncestor)
9147 ok(pGetAncestor(hwnd, GA_PARENT) != 0, "parent should NOT be unlinked at this point\n");
9148 if (test_DestroyWindow_flag)
9149 {
9150 DWORD style = GetWindowLongA(hwnd, GWL_STYLE);
9151 if (style & WS_CHILD)
9152 lParam = GetWindowLongPtrA(hwnd, GWLP_ID);
9153 else if (style & WS_POPUP)
9154 lParam = WND_POPUP_ID;
9155 else
9156 lParam = WND_PARENT_ID;
9157 }
9158 break;
9159
9160 /* test_accelerators() depends on this */
9161 case WM_NCHITTEST:
9162 return HTCLIENT;
9163
9164 case WM_USER+10:
9165 {
9166 ACTIVATION_CONTEXT_BASIC_INFORMATION basicinfo;
9167 HANDLE handle, event = (HANDLE)lParam;
9168 BOOL ret;
9169
9170 handle = (void*)0xdeadbeef;
9171 ret = pGetCurrentActCtx(&handle);
9172 ok(ret, "failed to get current context, %u\n", GetLastError());
9173 ok(handle == 0, "got active context %p\n", handle);
9174
9175 memset(&basicinfo, 0xff, sizeof(basicinfo));
9176 ret = pQueryActCtxW(QUERY_ACTCTX_FLAG_USE_ACTIVE_ACTCTX, handle, 0, ActivationContextBasicInformation,
9177 &basicinfo, sizeof(basicinfo), NULL);
9178 ok(ret, "got %d, error %d\n", ret, GetLastError());
9179 ok(basicinfo.hActCtx == NULL, "got %p\n", basicinfo.hActCtx);
9180 ok(basicinfo.dwFlags == 0, "got %x\n", basicinfo.dwFlags);
9181
9182 if (event) SetEvent(event);
9183 return 1;
9184 }
9185
9186 /* ignore */
9187 case WM_MOUSEMOVE:
9188 case WM_MOUSEACTIVATE:
9189 case WM_NCMOUSEMOVE:
9190 case WM_SETCURSOR:
9191 case WM_IME_SELECT:
9192 return 0;
9193 }
9194
9195 msg.hwnd = hwnd;
9196 msg.message = message;
9197 msg.flags = sent|wparam|lparam;
9198 if (defwndproc_counter) msg.flags |= defwinproc;
9199 if (beginpaint_counter) msg.flags |= beginpaint;
9200 msg.wParam = wParam;
9201 msg.lParam = lParam;
9202 msg.descr = "MsgCheckProc";
9203 add_message(&msg);
9204
9205 if (message == WM_GETMINMAXINFO && (GetWindowLongA(hwnd, GWL_STYLE) & WS_CHILD))
9206 {
9207 HWND parent = GetParent(hwnd);
9208 RECT rc;
9209 MINMAXINFO *minmax = (MINMAXINFO *)lParam;
9210
9211 GetClientRect(parent, &rc);
9212 trace("parent %p client size = (%d x %d)\n", parent, rc.right, rc.bottom);
9213 trace("Reserved=%d,%d MaxSize=%d,%d MaxPos=%d,%d MinTrack=%d,%d MaxTrack=%d,%d\n",
9214 minmax->ptReserved.x, minmax->ptReserved.y,
9215 minmax->ptMaxSize.x, minmax->ptMaxSize.y,
9216 minmax->ptMaxPosition.x, minmax->ptMaxPosition.y,
9217 minmax->ptMinTrackSize.x, minmax->ptMinTrackSize.y,
9218 minmax->ptMaxTrackSize.x, minmax->ptMaxTrackSize.y);
9219
9220 ok(minmax->ptMaxSize.x == rc.right, "default width of maximized child %d != %d\n",
9221 minmax->ptMaxSize.x, rc.right);
9222 ok(minmax->ptMaxSize.y == rc.bottom, "default height of maximized child %d != %d\n",
9223 minmax->ptMaxSize.y, rc.bottom);
9224 }
9225
9226 if (message == WM_PAINT)
9227 {
9228 PAINTSTRUCT ps;
9229 beginpaint_counter++;
9230 BeginPaint( hwnd, &ps );
9231 beginpaint_counter--;
9232 EndPaint( hwnd, &ps );
9233 return 0;
9234 }
9235
9236 if (message == WM_CONTEXTMENU)
9237 {
9238 /* don't create context menu */
9239 return 0;
9240 }
9241
9242 defwndproc_counter++;
9243 ret = unicode ? DefWindowProcW(hwnd, message, wParam, lParam)
9244 : DefWindowProcA(hwnd, message, wParam, lParam);
9245 defwndproc_counter--;
9246
9247 return ret;
9248 }
9249
9250 static LRESULT WINAPI MsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9251 {
9252 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
9253 }
9254
9255 static LRESULT WINAPI MsgCheckProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9256 {
9257 return MsgCheckProc (TRUE, hwnd, message, wParam, lParam);
9258 }
9259
9260 static LRESULT WINAPI PopupMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9261 {
9262 static LONG defwndproc_counter = 0;
9263 LRESULT ret;
9264 struct recvd_message msg;
9265
9266 if (ignore_message( message )) return 0;
9267
9268 switch (message)
9269 {
9270 case WM_QUERYENDSESSION:
9271 case WM_ENDSESSION:
9272 lParam &= ~0x01; /* Vista adds a 0x01 flag */
9273 break;
9274 }
9275
9276 msg.hwnd = hwnd;
9277 msg.message = message;
9278 msg.flags = sent|wparam|lparam;
9279 if (defwndproc_counter) msg.flags |= defwinproc;
9280 msg.wParam = wParam;
9281 msg.lParam = lParam;
9282 msg.descr = "popup";
9283 add_message(&msg);
9284
9285 if (message == WM_CREATE)
9286 {
9287 DWORD style = GetWindowLongA(hwnd, GWL_STYLE) | WS_VISIBLE;
9288 SetWindowLongA(hwnd, GWL_STYLE, style);
9289 }
9290
9291 defwndproc_counter++;
9292 ret = DefWindowProcA(hwnd, message, wParam, lParam);
9293 defwndproc_counter--;
9294
9295 return ret;
9296 }
9297
9298 static LRESULT WINAPI ParentMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9299 {
9300 static LONG defwndproc_counter = 0;
9301 static LONG beginpaint_counter = 0;
9302 LRESULT ret;
9303 struct recvd_message msg;
9304
9305 if (ignore_message( message )) return 0;
9306
9307 if (log_all_parent_messages ||
9308 message == WM_PARENTNOTIFY || message == WM_CANCELMODE ||
9309 message == WM_SETFOCUS || message == WM_KILLFOCUS ||
9310 message == WM_ENABLE || message == WM_ENTERIDLE ||
9311 message == WM_DRAWITEM || message == WM_MEASUREITEM || message == WM_COMPAREITEM ||
9312 message == WM_COMMAND || message == WM_IME_SETCONTEXT)
9313 {
9314 switch (message)
9315 {
9316 /* ignore */
9317 case WM_NCHITTEST:
9318 return HTCLIENT;
9319 case WM_SETCURSOR:
9320 case WM_MOUSEMOVE:
9321 case WM_NCMOUSEMOVE:
9322 return 0;
9323
9324 case WM_ERASEBKGND:
9325 {
9326 RECT rc;
9327 INT ret = GetClipBox((HDC)wParam, &rc);
9328
9329 trace("WM_ERASEBKGND: GetClipBox()=%d, %s\n", ret, wine_dbgstr_rect(&rc));
9330 break;
9331 }
9332 }
9333
9334 msg.hwnd = hwnd;
9335 msg.message = message;
9336 msg.flags = sent|parent|wparam|lparam;
9337 if (defwndproc_counter) msg.flags |= defwinproc;
9338 if (beginpaint_counter) msg.flags |= beginpaint;
9339 msg.wParam = wParam;
9340 msg.lParam = lParam;
9341 msg.descr = "parent";
9342 add_message(&msg);
9343 }
9344
9345 if (message == WM_PAINT)
9346 {
9347 PAINTSTRUCT ps;
9348 beginpaint_counter++;
9349 BeginPaint( hwnd, &ps );
9350 beginpaint_counter--;
9351 EndPaint( hwnd, &ps );
9352 return 0;
9353 }
9354
9355 defwndproc_counter++;
9356 ret = DefWindowProcA(hwnd, message, wParam, lParam);
9357 defwndproc_counter--;
9358
9359 return message == WM_COMPAREITEM ? -1 : ret;
9360 }
9361
9362 static INT_PTR CALLBACK StopQuitMsgCheckProcA(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
9363 {
9364 if (message == WM_CREATE)
9365 PostMessageA(hwnd, WM_CLOSE, 0, 0);
9366 else if (message == WM_CLOSE)
9367 {
9368 /* Only the first WM_QUIT will survive the window destruction */
9369 PostMessageA(hwnd, WM_USER, 0x1234, 0x5678);
9370 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
9371 PostMessageA(hwnd, WM_QUIT, 0x4321, 0x8765);
9372 }
9373
9374 return DefWindowProcA(hwnd, message, wp, lp);
9375 }
9376
9377 static LRESULT WINAPI TestDlgProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9378 {
9379 static LONG defwndproc_counter = 0;
9380 LRESULT ret;
9381 struct recvd_message msg;
9382
9383 if (ignore_message( message )) return 0;
9384
9385 if (test_def_id)
9386 {
9387 DefDlgProcA(hwnd, DM_SETDEFID, 1, 0);
9388 ret = DefDlgProcA(hwnd, DM_GETDEFID, 0, 0);
9389 if (after_end_dialog)
9390 ok( ret == 0, "DM_GETDEFID should return 0 after EndDialog, got %lx\n", ret );
9391 else
9392 ok(HIWORD(ret) == DC_HASDEFID, "DM_GETDEFID should return DC_HASDEFID, got %lx\n", ret);
9393 }
9394
9395 msg.hwnd = hwnd;
9396 msg.message = message;
9397 msg.flags = sent|wparam|lparam;
9398 if (defwndproc_counter) msg.flags |= defwinproc;
9399 msg.wParam = wParam;
9400 msg.lParam = lParam;
9401 msg.descr = "dialog";
9402 add_message(&msg);
9403
9404 defwndproc_counter++;
9405 ret = DefDlgProcA(hwnd, message, wParam, lParam);
9406 defwndproc_counter--;
9407
9408 return ret;
9409 }
9410
9411 static LRESULT WINAPI ShowWindowProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9412 {
9413 static LONG defwndproc_counter = 0;
9414 LRESULT ret;
9415 struct recvd_message msg;
9416
9417 /* log only specific messages we are interested in */
9418 switch (message)
9419 {
9420 #if 0 /* probably log these as well */
9421 case WM_ACTIVATE:
9422 case WM_SETFOCUS:
9423 case WM_KILLFOCUS:
9424 #endif
9425 case WM_SHOWWINDOW:
9426 case WM_SIZE:
9427 case WM_MOVE:
9428 case WM_GETMINMAXINFO:
9429 case WM_WINDOWPOSCHANGING:
9430 case WM_WINDOWPOSCHANGED:
9431 break;
9432
9433 default: /* ignore */
9434 /*trace("showwindow: %p, %04x, %08x, %08lx\n", hwnd, message, wParam, lParam);*/
9435 return DefWindowProcA(hwnd, message, wParam, lParam);
9436 }
9437
9438 msg.hwnd = hwnd;
9439 msg.message = message;
9440 msg.flags = sent|wparam|lparam;
9441 if (defwndproc_counter) msg.flags |= defwinproc;
9442 msg.wParam = wParam;
9443 msg.lParam = lParam;
9444 msg.descr = "show";
9445 add_message(&msg);
9446
9447 defwndproc_counter++;
9448 ret = DefWindowProcA(hwnd, message, wParam, lParam);
9449 defwndproc_counter--;
9450
9451 return ret;
9452 }
9453
9454 static LRESULT WINAPI PaintLoopProcA(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
9455 {
9456 switch (msg)
9457 {
9458 case WM_CREATE: return 0;
9459 case WM_PAINT:
9460 {
9461 MSG msg2;
9462 static int i = 0;
9463
9464 if (i < 256)
9465 {
9466 i++;
9467 if (PeekMessageA(&msg2, 0, 0, 0, 1))
9468 {
9469 TranslateMessage(&msg2);
9470 DispatchMessageA(&msg2);
9471 }
9472 i--;
9473 }
9474 else ok(broken(1), "infinite loop\n");
9475 if ( i == 0)
9476 paint_loop_done = TRUE;
9477 return DefWindowProcA(hWnd,msg,wParam,lParam);
9478 }
9479 }
9480 return DefWindowProcA(hWnd,msg,wParam,lParam);
9481 }
9482
9483 static LRESULT WINAPI HotkeyMsgCheckProcA(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
9484 {
9485 static LONG defwndproc_counter = 0;
9486 LRESULT ret;
9487 struct recvd_message msg;
9488 DWORD queue_status;
9489
9490 if (ignore_message( message )) return 0;
9491
9492 if ((message >= WM_KEYFIRST && message <= WM_KEYLAST) ||
9493 message == WM_HOTKEY || message >= WM_APP)
9494 {
9495 msg.hwnd = hwnd;
9496 msg.message = message;
9497 msg.flags = sent|wparam|lparam;
9498 if (defwndproc_counter) msg.flags |= defwinproc;
9499 msg.wParam = wParam;
9500 msg.lParam = lParam;
9501 msg.descr = "HotkeyMsgCheckProcA";
9502 add_message(&msg);
9503 }
9504
9505 defwndproc_counter++;
9506 ret = DefWindowProcA(hwnd, message, wParam, lParam);
9507 defwndproc_counter--;
9508
9509 if (message == WM_APP)
9510 {
9511 queue_status = GetQueueStatus(QS_HOTKEY);
9512 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
9513 queue_status = GetQueueStatus(QS_POSTMESSAGE);
9514 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
9515 PostMessageA(hwnd, WM_APP+1, 0, 0);
9516 }
9517 else if (message == WM_APP+1)
9518 {
9519 queue_status = GetQueueStatus(QS_HOTKEY);
9520 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
9521 }
9522
9523 return ret;
9524 }
9525
9526 static BOOL RegisterWindowClasses(void)
9527 {
9528 WNDCLASSA cls;
9529 WNDCLASSW clsW;
9530
9531 cls.style = 0;
9532 cls.lpfnWndProc = MsgCheckProcA;
9533 cls.cbClsExtra = 0;
9534 cls.cbWndExtra = 0;
9535 cls.hInstance = GetModuleHandleA(0);
9536 cls.hIcon = 0;
9537 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
9538 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
9539 cls.lpszMenuName = NULL;
9540 cls.lpszClassName = "TestWindowClass";
9541 if(!RegisterClassA(&cls)) return FALSE;
9542
9543 cls.lpfnWndProc = HotkeyMsgCheckProcA;
9544 cls.lpszClassName = "HotkeyWindowClass";
9545 if(!RegisterClassA(&cls)) return FALSE;
9546
9547 cls.lpfnWndProc = ShowWindowProcA;
9548 cls.lpszClassName = "ShowWindowClass";
9549 if(!RegisterClassA(&cls)) return FALSE;
9550
9551 cls.lpfnWndProc = PopupMsgCheckProcA;
9552 cls.lpszClassName = "TestPopupClass";
9553 if(!RegisterClassA(&cls)) return FALSE;
9554
9555 cls.lpfnWndProc = ParentMsgCheckProcA;
9556 cls.lpszClassName = "TestParentClass";
9557 if(!RegisterClassA(&cls)) return FALSE;
9558
9559 cls.lpfnWndProc = StopQuitMsgCheckProcA;
9560 cls.lpszClassName = "StopQuitClass";
9561 if(!RegisterClassA(&cls)) return FALSE;
9562
9563 cls.lpfnWndProc = DefWindowProcA;
9564 cls.lpszClassName = "SimpleWindowClass";
9565 if(!RegisterClassA(&cls)) return FALSE;
9566
9567 cls.lpfnWndProc = PaintLoopProcA;
9568 cls.lpszClassName = "PaintLoopWindowClass";
9569 if(!RegisterClassA(&cls)) return FALSE;
9570
9571 cls.style = CS_NOCLOSE;
9572 cls.lpszClassName = "NoCloseWindowClass";
9573 if(!RegisterClassA(&cls)) return FALSE;
9574
9575 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
9576 cls.style = 0;
9577 cls.hInstance = GetModuleHandleA(0);
9578 cls.hbrBackground = 0;
9579 cls.lpfnWndProc = TestDlgProcA;
9580 cls.lpszClassName = "TestDialogClass";
9581 if(!RegisterClassA(&cls)) return FALSE;
9582
9583 clsW.style = 0;
9584 clsW.lpfnWndProc = MsgCheckProcW;
9585 clsW.cbClsExtra = 0;
9586 clsW.cbWndExtra = 0;
9587 clsW.hInstance = GetModuleHandleW(0);
9588 clsW.hIcon = 0;
9589 clsW.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
9590 clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
9591 clsW.lpszMenuName = NULL;
9592 clsW.lpszClassName = testWindowClassW;
9593 RegisterClassW(&clsW); /* ignore error, this fails on Win9x */
9594
9595 return TRUE;
9596 }
9597
9598 static BOOL is_our_logged_class(HWND hwnd)
9599 {
9600 char buf[256];
9601
9602 if (GetClassNameA(hwnd, buf, sizeof(buf)))
9603 {
9604 if (!lstrcmpiA(buf, "TestWindowClass") ||
9605 !lstrcmpiA(buf, "ShowWindowClass") ||
9606 !lstrcmpiA(buf, "TestParentClass") ||
9607 !lstrcmpiA(buf, "TestPopupClass") ||
9608 !lstrcmpiA(buf, "SimpleWindowClass") ||
9609 !lstrcmpiA(buf, "TestDialogClass") ||
9610 !lstrcmpiA(buf, "MDI_frame_class") ||
9611 !lstrcmpiA(buf, "MDI_client_class") ||
9612 !lstrcmpiA(buf, "MDI_child_class") ||
9613 !lstrcmpiA(buf, "my_button_class") ||
9614 !lstrcmpiA(buf, "my_edit_class") ||
9615 !lstrcmpiA(buf, "static") ||
9616 !lstrcmpiA(buf, "ListBox") ||
9617 !lstrcmpiA(buf, "ComboBox") ||
9618 !lstrcmpiA(buf, "MyDialogClass") ||
9619 !lstrcmpiA(buf, "#32770") ||
9620 !lstrcmpiA(buf, "#32768"))
9621 return TRUE;
9622 }
9623 return FALSE;
9624 }
9625
9626 static LRESULT CALLBACK cbt_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
9627 {
9628 HWND hwnd;
9629
9630 ok(cbt_hook_thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
9631
9632 if (nCode == HCBT_CLICKSKIPPED)
9633 {
9634 /* ignore this event, XP sends it a lot when switching focus between windows */
9635 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9636 }
9637
9638 if (nCode == HCBT_SYSCOMMAND || nCode == HCBT_KEYSKIPPED)
9639 {
9640 struct recvd_message msg;
9641
9642 msg.hwnd = 0;
9643 msg.message = nCode;
9644 msg.flags = hook|wparam|lparam;
9645 msg.wParam = wParam;
9646 msg.lParam = lParam;
9647 msg.descr = "CBT";
9648 add_message(&msg);
9649
9650 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9651 }
9652
9653 if (nCode == HCBT_DESTROYWND)
9654 {
9655 if (test_DestroyWindow_flag)
9656 {
9657 DWORD style = GetWindowLongA((HWND)wParam, GWL_STYLE);
9658 if (style & WS_CHILD)
9659 lParam = GetWindowLongPtrA((HWND)wParam, GWLP_ID);
9660 else if (style & WS_POPUP)
9661 lParam = WND_POPUP_ID;
9662 else
9663 lParam = WND_PARENT_ID;
9664 }
9665 }
9666
9667 /* Log also SetFocus(0) calls */
9668 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
9669
9670 if (is_our_logged_class(hwnd))
9671 {
9672 struct recvd_message msg;
9673
9674 msg.hwnd = hwnd;
9675 msg.message = nCode;
9676 msg.flags = hook|wparam|lparam;
9677 msg.wParam = wParam;
9678 msg.lParam = lParam;
9679 msg.descr = "CBT";
9680 add_message(&msg);
9681 }
9682 return CallNextHookEx(hCBT_hook, nCode, wParam, lParam);
9683 }
9684
9685 static void CALLBACK win_event_proc(HWINEVENTHOOK hevent,
9686 DWORD event,
9687 HWND hwnd,
9688 LONG object_id,
9689 LONG child_id,
9690 DWORD thread_id,
9691 DWORD event_time)
9692 {
9693 ok(thread_id == GetCurrentThreadId(), "we didn't ask for events from other threads\n");
9694
9695 /* ignore mouse cursor events */
9696 if (object_id == OBJID_CURSOR) return;
9697
9698 if (!hwnd || is_our_logged_class(hwnd))
9699 {
9700 struct recvd_message msg;
9701
9702 msg.hwnd = hwnd;
9703 msg.message = event;
9704 msg.flags = winevent_hook|wparam|lparam;
9705 msg.wParam = object_id;
9706 msg.lParam = child_id;
9707 msg.descr = "WEH";
9708 add_message(&msg);
9709 }
9710 }
9711
9712 static const WCHAR wszUnicode[] = {'U','n','i','c','o','d','e',0};
9713 static const WCHAR wszAnsi[] = {'U',0};
9714
9715 static LRESULT CALLBACK MsgConversionProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
9716 {
9717 switch (uMsg)
9718 {
9719 case CB_FINDSTRINGEXACT:
9720 trace("String: %p\n", (LPCWSTR)lParam);
9721 if (!lstrcmpW((LPCWSTR)lParam, wszUnicode))
9722 return 1;
9723 if (!lstrcmpW((LPCWSTR)lParam, wszAnsi))
9724 return 0;
9725 return -1;
9726 }
9727 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
9728 }
9729
9730 static const struct message WmGetTextLengthAfromW[] = {
9731 { WM_GETTEXTLENGTH, sent },
9732 { WM_GETTEXT, sent|optional },
9733 { 0 }
9734 };
9735
9736 static const WCHAR dummy_window_text[] = {'d','u','m','m','y',' ','t','e','x','t',0};
9737
9738 /* dummy window proc for WM_GETTEXTLENGTH test */
9739 static LRESULT CALLBACK get_text_len_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
9740 {
9741 switch(msg)
9742 {
9743 case WM_GETTEXTLENGTH:
9744 return lstrlenW(dummy_window_text) + 37; /* some random length */
9745 case WM_GETTEXT:
9746 lstrcpynW( (LPWSTR)lp, dummy_window_text, wp );
9747 return lstrlenW( (LPWSTR)lp );
9748 default:
9749 return DefWindowProcW( hwnd, msg, wp, lp );
9750 }
9751 }
9752
9753 static void test_message_conversion(void)
9754 {
9755 static const WCHAR wszMsgConversionClass[] =
9756 {'M','s','g','C','o','n','v','e','r','s','i','o','n','C','l','a','s','s',0};
9757 WNDCLASSW cls;
9758 LRESULT lRes;
9759 HWND hwnd;
9760 WNDPROC wndproc, newproc;
9761 BOOL ret;
9762
9763 cls.style = 0;
9764 cls.lpfnWndProc = MsgConversionProcW;
9765 cls.cbClsExtra = 0;
9766 cls.cbWndExtra = 0;
9767 cls.hInstance = GetModuleHandleW(NULL);
9768 cls.hIcon = NULL;
9769 cls.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW);
9770 cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
9771 cls.lpszMenuName = NULL;
9772 cls.lpszClassName = wszMsgConversionClass;
9773 /* this call will fail on Win9x, but that doesn't matter as this test is
9774 * meaningless on those platforms */
9775 if(!RegisterClassW(&cls)) return;
9776
9777 hwnd = CreateWindowExW(0, wszMsgConversionClass, NULL, WS_OVERLAPPED,
9778 100, 100, 200, 200, 0, 0, 0, NULL);
9779 ok(hwnd != NULL, "Window creation failed\n");
9780
9781 /* {W, A} -> A */
9782
9783 wndproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
9784 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9785 ok(lRes == 0, "String should have been converted\n");
9786 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9787 ok(lRes == 1, "String shouldn't have been converted\n");
9788
9789 /* {W, A} -> W */
9790
9791 wndproc = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
9792 lRes = CallWindowProcA(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9793 ok(lRes == 1, "String shouldn't have been converted\n");
9794 lRes = CallWindowProcW(wndproc, hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9795 ok(lRes == 1, "String shouldn't have been converted\n");
9796
9797 /* Synchronous messages */
9798
9799 lRes = SendMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9800 ok(lRes == 0, "String should have been converted\n");
9801 lRes = SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9802 ok(lRes == 1, "String shouldn't have been converted\n");
9803
9804 /* Asynchronous messages */
9805
9806 SetLastError(0);
9807 lRes = PostMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9808 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9809 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9810 SetLastError(0);
9811 lRes = PostMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9812 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9813 "PostMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9814 SetLastError(0);
9815 lRes = PostThreadMessageA(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9816 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9817 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9818 SetLastError(0);
9819 lRes = PostThreadMessageW(GetCurrentThreadId(), CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9820 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9821 "PosThreadtMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9822 SetLastError(0);
9823 lRes = SendNotifyMessageA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9824 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9825 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9826 SetLastError(0);
9827 lRes = SendNotifyMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode);
9828 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9829 "SendNotifyMessage on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9830 SetLastError(0);
9831 lRes = SendMessageCallbackA(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
9832 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9833 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9834 SetLastError(0);
9835 lRes = SendMessageCallbackW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)wszUnicode, NULL, 0);
9836 ok(lRes == 0 && (GetLastError() == ERROR_MESSAGE_SYNC_ONLY || GetLastError() == ERROR_INVALID_PARAMETER),
9837 "SendMessageCallback on sync only message returned %ld, last error %d\n", lRes, GetLastError());
9838
9839 /* Check WM_GETTEXTLENGTH A->W behaviour, whether WM_GETTEXT is also sent or not */
9840
9841 hwnd = CreateWindowW (testWindowClassW, wszUnicode,
9842 WS_OVERLAPPEDWINDOW,
9843 100, 100, 200, 200, 0, 0, 0, NULL);
9844 assert(hwnd);
9845 flush_sequence();
9846 lRes = SendMessageA (hwnd, WM_GETTEXTLENGTH, 0, 0);
9847 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
9848 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
9849 "got bad length %ld\n", lRes );
9850
9851 flush_sequence();
9852 lRes = CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ),
9853 hwnd, WM_GETTEXTLENGTH, 0, 0);
9854 ok_sequence(WmGetTextLengthAfromW, "ANSI WM_GETTEXTLENGTH to Unicode window", FALSE);
9855 ok( lRes == WideCharToMultiByte( CP_ACP, 0, wszUnicode, lstrlenW(wszUnicode), NULL, 0, NULL, NULL ),
9856 "got bad length %ld\n", lRes );
9857
9858 wndproc = (WNDPROC)SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)get_text_len_proc );
9859 newproc = (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC );
9860 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
9861 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
9862 NULL, 0, NULL, NULL ) ||
9863 broken(lRes == lstrlenW(dummy_window_text) + 37),
9864 "got bad length %ld\n", lRes );
9865
9866 SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc ); /* restore old wnd proc */
9867 lRes = CallWindowProcA( newproc, hwnd, WM_GETTEXTLENGTH, 0, 0 );
9868 ok( lRes == WideCharToMultiByte( CP_ACP, 0, dummy_window_text, lstrlenW(dummy_window_text),
9869 NULL, 0, NULL, NULL ) ||
9870 broken(lRes == lstrlenW(dummy_window_text) + 37),
9871 "got bad length %ld\n", lRes );
9872
9873 ret = DestroyWindow(hwnd);
9874 ok( ret, "DestroyWindow() error %d\n", GetLastError());
9875 }
9876
9877 struct timer_info
9878 {
9879 HWND hWnd;
9880 HANDLE handles[2];
9881 DWORD id;
9882 };
9883
9884 static VOID CALLBACK tfunc(HWND hwnd, UINT uMsg, UINT_PTR id, DWORD dwTime)
9885 {
9886 }
9887
9888 #define TIMER_ID 0x19
9889 #define TIMER_COUNT_EXPECTED 100
9890 #define TIMER_COUNT_TOLERANCE 10
9891
9892 static int count = 0;
9893 static void CALLBACK callback_count(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
9894 {
9895 count++;
9896 }
9897
9898 static DWORD exception;
9899 static void CALLBACK callback_exception(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
9900 {
9901 count++;
9902 RaiseException(exception, 0, 0, NULL);
9903 }
9904
9905 static DWORD WINAPI timer_thread_proc(LPVOID x)
9906 {
9907 struct timer_info *info = x;
9908 DWORD r;
9909
9910 r = KillTimer(info->hWnd, 0x19);
9911 ok(r,"KillTimer failed in thread\n");
9912 r = SetTimer(info->hWnd,TIMER_ID,10000,tfunc);
9913 ok(r,"SetTimer failed in thread\n");
9914 ok(r==TIMER_ID,"SetTimer id different\n");
9915 r = SetEvent(info->handles[0]);
9916 ok(r,"SetEvent failed in thread\n");
9917 return 0;
9918 }
9919
9920 static void test_timers(void)
9921 {
9922 struct timer_info info;
9923 DWORD start;
9924 DWORD id;
9925 MSG msg;
9926
9927 info.hWnd = CreateWindowA("TestWindowClass", NULL,
9928 WS_OVERLAPPEDWINDOW ,
9929 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
9930 NULL, NULL, 0);
9931
9932 info.id = SetTimer(info.hWnd,TIMER_ID,10000,tfunc);
9933 ok(info.id, "SetTimer failed\n");
9934 ok(info.id==TIMER_ID, "SetTimer timer ID different\n");
9935 info.handles[0] = CreateEventW(NULL,0,0,NULL);
9936 info.handles[1] = CreateThread(NULL,0,timer_thread_proc,&info,0,&id);
9937
9938 WaitForMultipleObjects(2, info.handles, FALSE, INFINITE);
9939
9940 WaitForSingleObject(info.handles[1], INFINITE);
9941
9942 CloseHandle(info.handles[0]);
9943 CloseHandle(info.handles[1]);
9944
9945 ok( KillTimer(info.hWnd, TIMER_ID), "KillTimer failed\n");
9946
9947 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
9948 * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
9949 * 15.6 ms. Since there is some measurement error between test runs we are allowing for
9950 * ±9 counts (~4 ms) around the expected value.
9951 */
9952 count = 0;
9953 id = SetTimer(info.hWnd, TIMER_ID, 0, callback_count);
9954 ok(id != 0, "did not get id from SetTimer.\n");
9955 ok(id==TIMER_ID, "SetTimer timer ID different\n");
9956 start = GetTickCount();
9957 while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
9958 DispatchMessageA(&msg);
9959 todo_wine
9960 ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
9961 || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */
9962 || broken(abs(count-43) < TIMER_COUNT_TOLERANCE) /* w2k3, win8 */,
9963 "did not get expected count for minimum timeout (%d != ~%d).\n",
9964 count, TIMER_COUNT_EXPECTED);
9965 ok(KillTimer(info.hWnd, id), "KillTimer failed\n");
9966 /* Perform the same check on SetSystemTimer (only available on w2k3 and older) */
9967 if (pSetSystemTimer)
9968 {
9969 int syscount = 0;
9970
9971 count = 0;
9972 id = pSetSystemTimer(info.hWnd, TIMER_ID, 0, callback_count);
9973 ok(id != 0, "did not get id from SetSystemTimer.\n");
9974 ok(id==TIMER_ID, "SetTimer timer ID different\n");
9975 start = GetTickCount();
9976 while (GetTickCount()-start < 1001 && GetMessageA(&msg, info.hWnd, 0, 0))
9977 {
9978 if (msg.message == WM_SYSTIMER)
9979 syscount++;
9980 DispatchMessageA(&msg);
9981 }
9982 ok(abs(syscount-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE
9983 || broken(abs(syscount-64) < TIMER_COUNT_TOLERANCE) /* most common */
9984 || broken(syscount > 4000 && syscount < 12000) /* win2k3sp0 */,
9985 "did not get expected count for minimum timeout (%d != ~%d).\n",
9986 syscount, TIMER_COUNT_EXPECTED);
9987 todo_wine ok(count == 0, "did not get expected count for callback timeout (%d != 0).\n",
9988 count);
9989 ok(pKillSystemTimer(info.hWnd, id), "KillSystemTimer failed\n");
9990 }
9991
9992 ok(DestroyWindow(info.hWnd), "failed to destroy window\n");
9993 }
9994
9995 static void test_timers_no_wnd(void)
9996 {
9997 static UINT_PTR ids[0xffff];
9998 UINT_PTR id, id2;
9999 DWORD start;
10000 MSG msg;
10001 int i;
10002
10003 count = 0;
10004 id = SetTimer(NULL, 0, 100, callback_count);
10005 ok(id != 0, "did not get id from SetTimer.\n");
10006 id2 = SetTimer(NULL, id, 200, callback_count);
10007 ok(id2 == id, "did not get same id from SetTimer when replacing (%li expected %li).\n", id2, id);
10008 Sleep(150);
10009 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10010 ok(count == 0, "did not get zero count as expected (%i).\n", count);
10011 Sleep(150);
10012 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10013 ok(count == 1, "did not get one count as expected (%i).\n", count);
10014 KillTimer(NULL, id);
10015 Sleep(250);
10016 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
10017 ok(count == 1, "killing replaced timer did not work (%i).\n", count);
10018
10019 /* Check the minimum allowed timeout for a timer. MSDN indicates that it should be 10.0 ms,
10020 * which occurs sometimes, but most testing on the VMs indicates a minimum timeout closer to
10021 * 15.6 ms. Since there is some measurement error between test runs we are allowing for
10022 * ±9 counts (~4 ms) around the expected value.
10023 */
10024 count = 0;
10025 id = SetTimer(NULL, 0, 0, callback_count);
10026 ok(id != 0, "did not get id from SetTimer.\n");
10027 start = GetTickCount();
10028 while (GetTickCount()-start < 1001 && GetMessageA(&msg, NULL, 0, 0))
10029 DispatchMessageA(&msg);
10030 todo_wine
10031 ok(abs(count-TIMER_COUNT_EXPECTED) < TIMER_COUNT_TOLERANCE /* xp */
10032 || broken(abs(count-64) < TIMER_COUNT_TOLERANCE) /* most common */,
10033 "did not get expected count for minimum timeout (%d != ~%d).\n",
10034 count, TIMER_COUNT_EXPECTED);
10035 KillTimer(NULL, id);
10036 /* Note: SetSystemTimer doesn't support a NULL window, see test_timers */
10037
10038 if (pSetCoalescableTimer)
10039 {
10040 count = 0;
10041 id = pSetCoalescableTimer(NULL, 0, 0, callback_count, 0);
10042 ok(id != 0, "SetCoalescableTimer failed with %u.\n", GetLastError());
10043 start = GetTickCount();
10044 while (GetTickCount()-start < 100 && GetMessageA(&msg, NULL, 0, 0))
10045 DispatchMessageA(&msg);
10046 ok(count > 1, "expected count > 1, got %d.\n", count);
10047 KillTimer(NULL, id);
10048 }
10049 else
10050 win_skip("SetCoalescableTimer not available.\n");
10051
10052 /* Check what happens when we're running out of timers */
10053 for (i=0; i<sizeof(ids)/sizeof(ids[0]); i++)
10054 {
10055 SetLastError(0xdeadbeef);
10056 ids[i] = SetTimer(NULL, 0, USER_TIMER_MAXIMUM, tfunc);
10057 if (!ids[i]) break;
10058 }
10059 ok(i != sizeof(ids)/sizeof(ids[0]), "all timers were created successfully\n");
10060 ok(GetLastError()==ERROR_NO_MORE_USER_HANDLES || broken(GetLastError()==0xdeadbeef),
10061 "GetLastError() = %d\n", GetLastError());
10062 while (i > 0) KillTimer(NULL, ids[--i]);
10063 }
10064
10065 static void test_timers_exception(DWORD code)
10066 {
10067 UINT_PTR id;
10068 MSG msg;
10069
10070 exception = code;
10071 id = SetTimer(NULL, 0, 1000, callback_exception);
10072 ok(id != 0, "did not get id from SetTimer.\n");
10073
10074 memset(&msg, 0, sizeof(msg));
10075 msg.message = WM_TIMER;
10076 msg.wParam = id;
10077 msg.lParam = (LPARAM)callback_exception;
10078
10079 count = 0;
10080 DispatchMessageA(&msg);
10081 ok(count == 1, "did not get one count as expected (%i).\n", count);
10082
10083 KillTimer(NULL, id);
10084 }
10085
10086 static void test_timers_exceptions(void)
10087 {
10088 test_timers_exception(EXCEPTION_ACCESS_VIOLATION);
10089 test_timers_exception(EXCEPTION_DATATYPE_MISALIGNMENT);
10090 test_timers_exception(EXCEPTION_BREAKPOINT);
10091 test_timers_exception(EXCEPTION_SINGLE_STEP);
10092 test_timers_exception(EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
10093 test_timers_exception(EXCEPTION_FLT_DENORMAL_OPERAND);
10094 test_timers_exception(EXCEPTION_FLT_DIVIDE_BY_ZERO);
10095 test_timers_exception(EXCEPTION_FLT_INEXACT_RESULT);
10096 test_timers_exception(EXCEPTION_ILLEGAL_INSTRUCTION);
10097 test_timers_exception(0xE000BEEF); /* customer exception */
10098 }
10099
10100 /* Various win events with arbitrary parameters */
10101 static const struct message WmWinEventsSeq[] = {
10102 { EVENT_SYSTEM_SOUND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
10103 { EVENT_SYSTEM_ALERT, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
10104 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
10105 { EVENT_SYSTEM_MENUSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
10106 { EVENT_SYSTEM_MENUEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
10107 { EVENT_SYSTEM_MENUPOPUPSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
10108 { EVENT_SYSTEM_MENUPOPUPEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
10109 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
10110 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
10111 /* our win event hook ignores OBJID_CURSOR events */
10112 /*{ EVENT_SYSTEM_MOVESIZESTART, winevent_hook|wparam|lparam, OBJID_CURSOR, 9 },*/
10113 { EVENT_SYSTEM_MOVESIZEEND, winevent_hook|wparam|lparam, OBJID_ALERT, 10 },
10114 { EVENT_SYSTEM_CONTEXTHELPSTART, winevent_hook|wparam|lparam, OBJID_SOUND, 11 },
10115 { EVENT_SYSTEM_CONTEXTHELPEND, winevent_hook|wparam|lparam, OBJID_QUERYCLASSNAMEIDX, 12 },
10116 { EVENT_SYSTEM_DRAGDROPSTART, winevent_hook|wparam|lparam, OBJID_NATIVEOM, 13 },
10117 { EVENT_SYSTEM_DRAGDROPEND, winevent_hook|wparam|lparam, OBJID_WINDOW, 0 },
10118 { EVENT_SYSTEM_DIALOGSTART, winevent_hook|wparam|lparam, OBJID_SYSMENU, 1 },
10119 { EVENT_SYSTEM_DIALOGEND, winevent_hook|wparam|lparam, OBJID_TITLEBAR, 2 },
10120 { EVENT_SYSTEM_SCROLLINGSTART, winevent_hook|wparam|lparam, OBJID_MENU, 3 },
10121 { EVENT_SYSTEM_SCROLLINGEND, winevent_hook|wparam|lparam, OBJID_CLIENT, 4 },
10122 { EVENT_SYSTEM_SWITCHSTART, winevent_hook|wparam|lparam, OBJID_VSCROLL, 5 },
10123 { EVENT_SYSTEM_SWITCHEND, winevent_hook|wparam|lparam, OBJID_HSCROLL, 6 },
10124 { EVENT_SYSTEM_MINIMIZESTART, winevent_hook|wparam|lparam, OBJID_SIZEGRIP, 7 },
10125 { EVENT_SYSTEM_MINIMIZEEND, winevent_hook|wparam|lparam, OBJID_CARET, 8 },
10126 { 0 }
10127 };
10128 static const struct message WmWinEventCaretSeq[] = {
10129 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10130 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10131 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 2 */
10132 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1 */
10133 { 0 }
10134 };
10135 static const struct message WmWinEventCaretSeq_2[] = {
10136 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10137 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10138 { EVENT_OBJECT_NAMECHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 }, /* hook 1/2 */
10139 { 0 }
10140 };
10141 static const struct message WmWinEventAlertSeq[] = {
10142 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 0 },
10143 { 0 }
10144 };
10145 static const struct message WmWinEventAlertSeq_2[] = {
10146 /* create window in the thread proc */
10147 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_WINDOW, 2 },
10148 /* our test event */
10149 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_ALERT, 2 },
10150 { 0 }
10151 };
10152 static const struct message WmGlobalHookSeq_1[] = {
10153 /* create window in the thread proc */
10154 { HCBT_CREATEWND, hook|lparam, 0, 2 },
10155 /* our test events */
10156 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 },
10157 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 },
10158 { 0 }
10159 };
10160 static const struct message WmGlobalHookSeq_2[] = {
10161 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 0 }, /* old local hook */
10162 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_NEXTWINDOW, 2 }, /* new global hook */
10163 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 0 }, /* old local hook */
10164 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_PREVWINDOW, 2 }, /* new global hook */
10165 { 0 }
10166 };
10167
10168 static const struct message WmMouseLLHookSeq[] = {
10169 { WM_MOUSEMOVE, hook },
10170 { WM_LBUTTONUP, hook },
10171 { WM_MOUSEMOVE, hook },
10172 { 0 }
10173 };
10174
10175 static void CALLBACK win_event_global_hook_proc(HWINEVENTHOOK hevent,
10176 DWORD event,
10177 HWND hwnd,
10178 LONG object_id,
10179 LONG child_id,
10180 DWORD thread_id,
10181 DWORD event_time)
10182 {
10183 char buf[256];
10184
10185 if (GetClassNameA(hwnd, buf, sizeof(buf)))
10186 {
10187 if (!lstrcmpiA(buf, "TestWindowClass") ||
10188 !lstrcmpiA(buf, "static"))
10189 {
10190 struct recvd_message msg;
10191
10192 msg.hwnd = hwnd;
10193 msg.message = event;
10194 msg.flags = winevent_hook|wparam|lparam;
10195 msg.wParam = object_id;
10196 msg.lParam = (thread_id == GetCurrentThreadId()) ? child_id : (child_id + 2);
10197 msg.descr = "WEH_2";
10198 add_message(&msg);
10199 }
10200 }
10201 }
10202
10203 static HHOOK hCBT_global_hook;
10204 static DWORD cbt_global_hook_thread_id;
10205
10206 static LRESULT CALLBACK cbt_global_hook_proc(int nCode, WPARAM wParam, LPARAM lParam)
10207 {
10208 HWND hwnd;
10209 char buf[256];
10210
10211 if (nCode == HCBT_SYSCOMMAND)
10212 {
10213 struct recvd_message msg;
10214
10215 msg.hwnd = 0;
10216 msg.message = nCode;
10217 msg.flags = hook|wparam|lparam;
10218 msg.wParam = wParam;
10219 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
10220 msg.descr = "CBT_2";
10221 add_message(&msg);
10222
10223 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10224 }
10225 /* WH_MOUSE_LL hook */
10226 if (nCode == HC_ACTION)
10227 {
10228 MSLLHOOKSTRUCT *mhll = (MSLLHOOKSTRUCT *)lParam;
10229
10230 /* we can't test for real mouse events */
10231 if (mhll->flags & LLMHF_INJECTED)
10232 {
10233 struct recvd_message msg;
10234
10235 memset (&msg, 0, sizeof (msg));
10236 msg.message = wParam;
10237 msg.flags = hook;
10238 msg.descr = "CBT_2";
10239 add_message(&msg);
10240 }
10241 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10242 }
10243
10244 /* Log also SetFocus(0) calls */
10245 hwnd = wParam ? (HWND)wParam : (HWND)lParam;
10246
10247 if (GetClassNameA(hwnd, buf, sizeof(buf)))
10248 {
10249 if (!lstrcmpiA(buf, "TestWindowClass") ||
10250 !lstrcmpiA(buf, "static"))
10251 {
10252 struct recvd_message msg;
10253
10254 msg.hwnd = hwnd;
10255 msg.message = nCode;
10256 msg.flags = hook|wparam|lparam;
10257 msg.wParam = wParam;
10258 msg.lParam = (cbt_global_hook_thread_id == GetCurrentThreadId()) ? 1 : 2;
10259 msg.descr = "CBT_2";
10260 add_message(&msg);
10261 }
10262 }
10263 return CallNextHookEx(hCBT_global_hook, nCode, wParam, lParam);
10264 }
10265
10266 static DWORD WINAPI win_event_global_thread_proc(void *param)
10267 {
10268 HWND hwnd;
10269 MSG msg;
10270 HANDLE hevent = *(HANDLE *)param;
10271
10272 assert(pNotifyWinEvent);
10273
10274 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10275 assert(hwnd);
10276 trace("created thread window %p\n", hwnd);
10277
10278 *(HWND *)param = hwnd;
10279
10280 flush_sequence();
10281 /* this event should be received only by our new hook proc,
10282 * an old one does not expect an event from another thread.
10283 */
10284 pNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, hwnd, OBJID_ALERT, 0);
10285 SetEvent(hevent);
10286
10287 while (GetMessageA(&msg, 0, 0, 0))
10288 {
10289 TranslateMessage(&msg);
10290 DispatchMessageA(&msg);
10291 }
10292 return 0;
10293 }
10294
10295 static DWORD WINAPI cbt_global_hook_thread_proc(void *param)
10296 {
10297 HWND hwnd;
10298 MSG msg;
10299 HANDLE hevent = *(HANDLE *)param;
10300
10301 flush_sequence();
10302 /* these events should be received only by our new hook proc,
10303 * an old one does not expect an event from another thread.
10304 */
10305
10306 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10307 assert(hwnd);
10308 trace("created thread window %p\n", hwnd);
10309
10310 *(HWND *)param = hwnd;
10311
10312 /* Windows doesn't like when a thread plays games with the focus,
10313 that leads to all kinds of misbehaviours and failures to activate
10314 a window. So, better keep next lines commented out.
10315 SetFocus(0);
10316 SetFocus(hwnd);*/
10317
10318 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
10319 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
10320
10321 SetEvent(hevent);
10322
10323 while (GetMessageA(&msg, 0, 0, 0))
10324 {
10325 TranslateMessage(&msg);
10326 DispatchMessageA(&msg);
10327 }
10328 return 0;
10329 }
10330
10331 static DWORD WINAPI mouse_ll_global_thread_proc(void *param)
10332 {
10333 HWND hwnd;
10334 MSG msg;
10335 HANDLE hevent = *(HANDLE *)param;
10336
10337 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
10338 assert(hwnd);
10339 trace("created thread window %p\n", hwnd);
10340
10341 *(HWND *)param = hwnd;
10342
10343 flush_sequence();
10344
10345 /* Windows doesn't like when a thread plays games with the focus,
10346 * that leads to all kinds of misbehaviours and failures to activate
10347 * a window. So, better don't generate a mouse click message below.
10348 */
10349 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10350 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
10351 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10352
10353 SetEvent(hevent);
10354 while (GetMessageA(&msg, 0, 0, 0))
10355 {
10356 TranslateMessage(&msg);
10357 DispatchMessageA(&msg);
10358 }
10359 return 0;
10360 }
10361
10362 static void test_winevents(void)
10363 {
10364 BOOL ret;
10365 MSG msg;
10366 HWND hwnd, hwnd2;
10367 UINT i;
10368 HANDLE hthread, hevent;
10369 DWORD tid;
10370 HWINEVENTHOOK hhook;
10371 const struct message *events = WmWinEventsSeq;
10372
10373 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
10374 WS_OVERLAPPEDWINDOW,
10375 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
10376 NULL, NULL, 0);
10377 assert(hwnd);
10378
10379 /****** start of global hook test *************/
10380 hCBT_global_hook = SetWindowsHookExA(WH_CBT, cbt_global_hook_proc, GetModuleHandleA(0), 0);
10381 if (!hCBT_global_hook)
10382 {
10383 ok(DestroyWindow(hwnd), "failed to destroy window\n");
10384 skip( "cannot set global hook\n" );
10385 return;
10386 }
10387
10388 hevent = CreateEventA(NULL, 0, 0, NULL);
10389 assert(hevent);
10390 hwnd2 = hevent;
10391
10392 hthread = CreateThread(NULL, 0, cbt_global_hook_thread_proc, &hwnd2, 0, &tid);
10393 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10394
10395 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10396
10397 ok_sequence(WmGlobalHookSeq_1, "global hook 1", FALSE);
10398
10399 flush_sequence();
10400 /* this one should be received only by old hook proc */
10401 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_NEXTWINDOW, 0);
10402 /* this one should be received only by old hook proc */
10403 DefWindowProcA(hwnd, WM_SYSCOMMAND, SC_PREVWINDOW, 0);
10404
10405 ok_sequence(WmGlobalHookSeq_2, "global hook 2", FALSE);
10406
10407 ret = UnhookWindowsHookEx(hCBT_global_hook);
10408 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
10409
10410 PostThreadMessageA(tid, WM_QUIT, 0, 0);
10411 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10412 CloseHandle(hthread);
10413 CloseHandle(hevent);
10414 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10415 /****** end of global hook test *************/
10416
10417 if (!pSetWinEventHook || !pNotifyWinEvent || !pUnhookWinEvent)
10418 {
10419 ok(DestroyWindow(hwnd), "failed to destroy window\n");
10420 return;
10421 }
10422
10423 flush_sequence();
10424
10425 if (0)
10426 {
10427 /* this test doesn't pass under Win9x */
10428 /* win2k ignores events with hwnd == 0 */
10429 SetLastError(0xdeadbeef);
10430 pNotifyWinEvent(events[0].message, 0, events[0].wParam, events[0].lParam);
10431 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || /* Win2k */
10432 GetLastError() == 0xdeadbeef, /* Win9x */
10433 "unexpected error %d\n", GetLastError());
10434 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
10435 }
10436
10437 for (i = 0; i < sizeof(WmWinEventsSeq)/sizeof(WmWinEventsSeq[0]); i++)
10438 pNotifyWinEvent(events[i].message, hwnd, events[i].wParam, events[i].lParam);
10439
10440 ok_sequence(WmWinEventsSeq, "notify winevents", FALSE);
10441
10442 /****** start of event filtering test *************/
10443 hhook = pSetWinEventHook(
10444 EVENT_OBJECT_SHOW, /* 0x8002 */
10445 EVENT_OBJECT_LOCATIONCHANGE, /* 0x800B */
10446 GetModuleHandleA(0), win_event_global_hook_proc,
10447 GetCurrentProcessId(), 0,
10448 WINEVENT_INCONTEXT);
10449 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
10450
10451 hevent = CreateEventA(NULL, 0, 0, NULL);
10452 assert(hevent);
10453 hwnd2 = hevent;
10454
10455 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
10456 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10457
10458 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10459
10460 ok_sequence(WmWinEventAlertSeq, "alert winevent", FALSE);
10461
10462 flush_sequence();
10463 /* this one should be received only by old hook proc */
10464 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
10465 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
10466 /* this one should be received only by old hook proc */
10467 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
10468
10469 ok_sequence(WmWinEventCaretSeq, "caret winevent", FALSE);
10470
10471 ret = pUnhookWinEvent(hhook);
10472 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10473
10474 PostThreadMessageA(tid, WM_QUIT, 0, 0);
10475 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10476 CloseHandle(hthread);
10477 CloseHandle(hevent);
10478 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10479 /****** end of event filtering test *************/
10480
10481 /****** start of out of context event test *************/
10482 hhook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0,
10483 win_event_global_hook_proc, GetCurrentProcessId(), 0,
10484 WINEVENT_OUTOFCONTEXT);
10485 ok(hhook != 0, "SetWinEventHook error %d\n", GetLastError());
10486
10487 hevent = CreateEventA(NULL, 0, 0, NULL);
10488 assert(hevent);
10489 hwnd2 = hevent;
10490
10491 flush_sequence();
10492
10493 hthread = CreateThread(NULL, 0, win_event_global_thread_proc, &hwnd2, 0, &tid);
10494 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10495
10496 ok(WaitForSingleObject(hevent, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10497
10498 ok_sequence(WmEmptySeq, "empty notify winevents", FALSE);
10499 /* process pending winevent messages */
10500 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
10501 ok_sequence(WmWinEventAlertSeq_2, "alert winevent for out of context proc", FALSE);
10502
10503 flush_sequence();
10504 /* this one should be received only by old hook proc */
10505 pNotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_CARET, 0); /* 0x8000 */
10506 pNotifyWinEvent(EVENT_OBJECT_SHOW, hwnd, OBJID_CARET, 0); /* 0x8002 */
10507 /* this one should be received only by old hook proc */
10508 pNotifyWinEvent(EVENT_OBJECT_NAMECHANGE, hwnd, OBJID_CARET, 0); /* 0x800C */
10509
10510 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for incontext proc", FALSE);
10511 /* process pending winevent messages */
10512 ok(!PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "msg queue should be empty\n");
10513 ok_sequence(WmWinEventCaretSeq_2, "caret winevent for out of context proc", FALSE);
10514
10515 ret = pUnhookWinEvent(hhook);
10516 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10517
10518 PostThreadMessageA(tid, WM_QUIT, 0, 0);
10519 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10520 CloseHandle(hthread);
10521 CloseHandle(hevent);
10522 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10523 /****** end of out of context event test *************/
10524
10525 /****** start of MOUSE_LL hook test *************/
10526 hCBT_global_hook = SetWindowsHookExA(WH_MOUSE_LL, cbt_global_hook_proc, GetModuleHandleA(0), 0);
10527 /* WH_MOUSE_LL is not supported on Win9x platforms */
10528 if (!hCBT_global_hook)
10529 {
10530 win_skip("Skipping WH_MOUSE_LL test on this platform\n");
10531 goto skip_mouse_ll_hook_test;
10532 }
10533
10534 hevent = CreateEventA(NULL, 0, 0, NULL);
10535 assert(hevent);
10536 hwnd2 = hevent;
10537
10538 hthread = CreateThread(NULL, 0, mouse_ll_global_thread_proc, &hwnd2, 0, &tid);
10539 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
10540
10541 while (WaitForSingleObject(hevent, 100) == WAIT_TIMEOUT)
10542 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
10543
10544 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook other thread", FALSE);
10545 flush_sequence();
10546
10547 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
10548 mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
10549 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
10550
10551 ok_sequence(WmMouseLLHookSeq, "MOUSE_LL hook same thread", FALSE);
10552
10553 ret = UnhookWindowsHookEx(hCBT_global_hook);
10554 ok( ret, "UnhookWindowsHookEx error %d\n", GetLastError());
10555
10556 PostThreadMessageA(tid, WM_QUIT, 0, 0);
10557 ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
10558 CloseHandle(hthread);
10559 CloseHandle(hevent);
10560 ok(!IsWindow(hwnd2), "window should be destroyed on thread exit\n");
10561 /****** end of MOUSE_LL hook test *************/
10562 skip_mouse_ll_hook_test:
10563
10564 ok(DestroyWindow(hwnd), "failed to destroy window\n");
10565 }
10566
10567 static void test_set_hook(void)
10568 {
10569 BOOL ret;
10570 HHOOK hhook;
10571 HWINEVENTHOOK hwinevent_hook;
10572
10573 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, GetModuleHandleA(0), GetCurrentThreadId());
10574 ok(hhook != 0, "local hook does not require hModule set to 0\n");
10575 UnhookWindowsHookEx(hhook);
10576
10577 if (0)
10578 {
10579 /* this test doesn't pass under Win9x: BUG! */
10580 SetLastError(0xdeadbeef);
10581 hhook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, 0);
10582 ok(!hhook, "global hook requires hModule != 0\n");
10583 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD, "unexpected error %d\n", GetLastError());
10584 }
10585
10586 SetLastError(0xdeadbeef);
10587 hhook = SetWindowsHookExA(WH_CBT, 0, GetModuleHandleA(0), GetCurrentThreadId());
10588 ok(!hhook, "SetWinEventHook with invalid proc should fail\n");
10589 ok(GetLastError() == ERROR_INVALID_FILTER_PROC || /* Win2k */
10590 GetLastError() == 0xdeadbeef, /* Win9x */
10591 "unexpected error %d\n", GetLastError());
10592
10593 SetLastError(0xdeadbeef);
10594 ok(!UnhookWindowsHookEx((HHOOK)0xdeadbeef), "UnhookWindowsHookEx succeeded\n");
10595 ok(GetLastError() == ERROR_INVALID_HOOK_HANDLE || /* Win2k */
10596 GetLastError() == 0xdeadbeef, /* Win9x */
10597 "unexpected error %d\n", GetLastError());
10598
10599 if (!pSetWinEventHook || !pUnhookWinEvent) return;
10600
10601 /* even process local incontext hooks require hmodule */
10602 SetLastError(0xdeadbeef);
10603 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10604 GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
10605 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
10606 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
10607 GetLastError() == 0xdeadbeef, /* Win9x */
10608 "unexpected error %d\n", GetLastError());
10609
10610 /* even thread local incontext hooks require hmodule */
10611 SetLastError(0xdeadbeef);
10612 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10613 GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_INCONTEXT);
10614 ok(!hwinevent_hook, "WINEVENT_INCONTEXT requires hModule != 0\n");
10615 ok(GetLastError() == ERROR_HOOK_NEEDS_HMOD || /* Win2k */
10616 GetLastError() == 0xdeadbeef, /* Win9x */
10617 "unexpected error %d\n", GetLastError());
10618
10619 if (0)
10620 {
10621 /* these 3 tests don't pass under Win9x */
10622 SetLastError(0xdeadbeef);
10623 hwinevent_hook = pSetWinEventHook(1, 0, 0, win_event_proc,
10624 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10625 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
10626 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
10627
10628 SetLastError(0xdeadbeef);
10629 hwinevent_hook = pSetWinEventHook(-1, 1, 0, win_event_proc,
10630 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10631 ok(!hwinevent_hook, "SetWinEventHook with invalid event range should fail\n");
10632 ok(GetLastError() == ERROR_INVALID_HOOK_FILTER, "unexpected error %d\n", GetLastError());
10633
10634 SetLastError(0xdeadbeef);
10635 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10636 0, 0xdeadbeef, WINEVENT_OUTOFCONTEXT);
10637 ok(!hwinevent_hook, "SetWinEventHook with invalid tid should fail\n");
10638 ok(GetLastError() == ERROR_INVALID_THREAD_ID, "unexpected error %d\n", GetLastError());
10639 }
10640
10641 SetLastError(0xdeadbeef);
10642 hwinevent_hook = pSetWinEventHook(0, 0, 0, win_event_proc,
10643 GetCurrentProcessId(), 0, WINEVENT_OUTOFCONTEXT);
10644 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
10645 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
10646 ret = pUnhookWinEvent(hwinevent_hook);
10647 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10648
10649 todo_wine {
10650 /* This call succeeds under win2k SP4, but fails under Wine.
10651 Does win2k test/use passed process id? */
10652 SetLastError(0xdeadbeef);
10653 hwinevent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX, 0, win_event_proc,
10654 0xdeadbeef, 0, WINEVENT_OUTOFCONTEXT);
10655 ok(hwinevent_hook != 0, "SetWinEventHook error %d\n", GetLastError());
10656 ok(GetLastError() == 0xdeadbeef, "unexpected error %d\n", GetLastError());
10657 ret = pUnhookWinEvent(hwinevent_hook);
10658 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
10659 }
10660
10661 SetLastError(0xdeadbeef);
10662 ok(!pUnhookWinEvent((HWINEVENTHOOK)0xdeadbeef), "UnhookWinEvent succeeded\n");
10663 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
10664 GetLastError() == 0xdeadbeef, /* Win9x */
10665 "unexpected error %d\n", GetLastError());
10666 }
10667
10668 static HWND hook_hwnd;
10669 static HHOOK recursive_hook;
10670 static int hook_depth, max_hook_depth;
10671
10672 static LRESULT WINAPI rec_get_message_hook(int code, WPARAM w, LPARAM l)
10673 {
10674 LRESULT res;
10675 MSG msg;
10676 BOOL b;
10677
10678 hook_depth++;
10679 if(hook_depth > max_hook_depth)
10680 max_hook_depth = hook_depth;
10681
10682 b = PeekMessageW(&msg, hook_hwnd, 0, 0, PM_NOREMOVE);
10683 ok(b, "PeekMessage failed\n");
10684
10685 res = CallNextHookEx(recursive_hook, code, w, l);
10686
10687 hook_depth--;
10688 return res;
10689 }
10690
10691 static void test_recursive_hook(void)
10692 {
10693 MSG msg;
10694 BOOL b;
10695
10696 hook_hwnd = CreateWindowA("Static", NULL, WS_POPUP, 0, 0, 200, 60, NULL, NULL, NULL, NULL);
10697 ok(hook_hwnd != NULL, "CreateWindow failed\n");
10698
10699 recursive_hook = SetWindowsHookExW(WH_GETMESSAGE, rec_get_message_hook, NULL, GetCurrentThreadId());
10700 ok(recursive_hook != NULL, "SetWindowsHookEx failed\n");
10701
10702 PostMessageW(hook_hwnd, WM_USER, 0, 0);
10703 PostMessageW(hook_hwnd, WM_USER+1, 0, 0);
10704
10705 hook_depth = 0;
10706 GetMessageW(&msg, hook_hwnd, 0, 0);
10707 ok(15 <= max_hook_depth && max_hook_depth < 45, "max_hook_depth = %d\n", max_hook_depth);
10708 trace("max_hook_depth = %d\n", max_hook_depth);
10709
10710 b = UnhookWindowsHookEx(recursive_hook);
10711 ok(b, "UnhokWindowsHookEx failed\n");
10712
10713 DestroyWindow(hook_hwnd);
10714 }
10715
10716 static const struct message ScrollWindowPaint1[] = {
10717 { WM_PAINT, sent },
10718 { WM_ERASEBKGND, sent|beginpaint },
10719 { WM_GETTEXTLENGTH, sent|optional },
10720 { WM_PAINT, sent|optional },
10721 { WM_NCPAINT, sent|beginpaint|optional },
10722 { WM_GETTEXT, sent|beginpaint|optional },
10723 { WM_GETTEXT, sent|beginpaint|optional },
10724 { WM_GETTEXT, sent|beginpaint|optional },
10725 { WM_GETTEXT, sent|beginpaint|defwinproc|optional },
10726 { WM_ERASEBKGND, sent|beginpaint|optional },
10727 { 0 }
10728 };
10729
10730 static const struct message ScrollWindowPaint2[] = {
10731 { WM_PAINT, sent },
10732 { 0 }
10733 };
10734
10735 static void test_scrollwindowex(void)
10736 {
10737 HWND hwnd, hchild;
10738 RECT rect={0,0,130,130};
10739
10740 hwnd = CreateWindowExA(0, "TestWindowClass", "Test Scroll",
10741 WS_VISIBLE|WS_OVERLAPPEDWINDOW,
10742 100, 100, 200, 200, 0, 0, 0, NULL);
10743 ok (hwnd != 0, "Failed to create overlapped window\n");
10744 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
10745 WS_VISIBLE|WS_CAPTION|WS_CHILD,
10746 10, 10, 150, 150, hwnd, 0, 0, NULL);
10747 ok (hchild != 0, "Failed to create child\n");
10748 UpdateWindow(hwnd);
10749 flush_events();
10750 flush_sequence();
10751
10752 /* scroll without the child window */
10753 trace("start scroll\n");
10754 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
10755 SW_ERASE|SW_INVALIDATE);
10756 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
10757 trace("end scroll\n");
10758 flush_sequence();
10759 flush_events();
10760 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
10761 flush_events();
10762 flush_sequence();
10763
10764 /* Now without the SW_ERASE flag */
10765 trace("start scroll\n");
10766 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL, SW_INVALIDATE);
10767 ok_sequence(WmEmptySeq, "ScrollWindowEx", FALSE);
10768 trace("end scroll\n");
10769 flush_sequence();
10770 flush_events();
10771 ok_sequence(ScrollWindowPaint2, "ScrollWindowEx", FALSE);
10772 flush_events();
10773 flush_sequence();
10774
10775 /* now scroll the child window as well */
10776 trace("start scroll\n");
10777 ScrollWindowEx( hwnd, 10, 10, &rect, NULL, NULL, NULL,
10778 SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
10779 /* wine sends WM_POSCHANGING, WM_POSCHANGED messages */
10780 /* windows sometimes a WM_MOVE */
10781 ok_sequence(WmEmptySeq, "ScrollWindowEx", TRUE);
10782 trace("end scroll\n");
10783 flush_sequence();
10784 flush_events();
10785 ok_sequence(ScrollWindowPaint1, "ScrollWindowEx", FALSE);
10786 flush_events();
10787 flush_sequence();
10788
10789 /* now scroll with ScrollWindow() */
10790 trace("start scroll with ScrollWindow\n");
10791 ScrollWindow( hwnd, 5, 5, NULL, NULL);
10792 trace("end scroll\n");
10793 flush_sequence();
10794 flush_events();
10795 ok_sequence(ScrollWindowPaint1, "ScrollWindow", FALSE);
10796
10797 ok(DestroyWindow(hchild), "failed to destroy window\n");
10798 ok(DestroyWindow(hwnd), "failed to destroy window\n");
10799 flush_sequence();
10800 }
10801
10802 static const struct message destroy_window_with_children[] = {
10803 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
10804 { HCBT_DESTROYWND, hook|lparam, 0, WND_PARENT_ID }, /* parent */
10805 { 0x0090, sent|optional },
10806 { HCBT_DESTROYWND, hook|lparam, 0, WND_POPUP_ID }, /* popup */
10807 { 0x0090, sent|optional },
10808 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* popup */
10809 { WM_DESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
10810 { WM_CAPTURECHANGED, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
10811 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_POPUP_ID }, /* popup */
10812 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, 0, 0 }, /* parent */
10813 { WM_DESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
10814 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
10815 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
10816 { WM_DESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
10817 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 2 }, /* child2 */
10818 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 3 }, /* child3 */
10819 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_CHILD_ID + 1 }, /* child1 */
10820 { WM_NCDESTROY, sent|wparam|lparam, 0, WND_PARENT_ID }, /* parent */
10821 { 0 }
10822 };
10823
10824 static void test_DestroyWindow(void)
10825 {
10826 BOOL ret;
10827 HWND parent, child1, child2, child3, child4, test;
10828 UINT_PTR child_id = WND_CHILD_ID + 1;
10829
10830 parent = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
10831 100, 100, 200, 200, 0, 0, 0, NULL);
10832 assert(parent != 0);
10833 child1 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
10834 0, 0, 50, 50, parent, (HMENU)child_id++, 0, NULL);
10835 assert(child1 != 0);
10836 child2 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
10837 0, 0, 50, 50, GetDesktopWindow(), (HMENU)child_id++, 0, NULL);
10838 assert(child2 != 0);
10839 child3 = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
10840 0, 0, 50, 50, child1, (HMENU)child_id++, 0, NULL);
10841 assert(child3 != 0);
10842 child4 = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP,
10843 0, 0, 50, 50, parent, 0, 0, NULL);
10844 assert(child4 != 0);
10845
10846 /* test owner/parent of child2 */
10847 test = GetParent(child2);
10848 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
10849 ok(!IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
10850 if(pGetAncestor) {
10851 test = pGetAncestor(child2, GA_PARENT);
10852 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
10853 }
10854 test = GetWindow(child2, GW_OWNER);
10855 ok(!test, "wrong owner %p\n", test);
10856
10857 test = SetParent(child2, parent);
10858 ok(test == GetDesktopWindow(), "wrong old parent %p\n", test);
10859
10860 /* test owner/parent of the parent */
10861 test = GetParent(parent);
10862 ok(!test, "wrong parent %p\n", test);
10863 ok(!IsChild(GetDesktopWindow(), parent), "wrong parent/child %p/%p\n", GetDesktopWindow(), parent);
10864 if(pGetAncestor) {
10865 test = pGetAncestor(parent, GA_PARENT);
10866 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
10867 }
10868 test = GetWindow(parent, GW_OWNER);
10869 ok(!test, "wrong owner %p\n", test);
10870
10871 /* test owner/parent of child1 */
10872 test = GetParent(child1);
10873 ok(test == parent, "wrong parent %p\n", test);
10874 ok(IsChild(parent, child1), "wrong parent/child %p/%p\n", parent, child1);
10875 if(pGetAncestor) {
10876 test = pGetAncestor(child1, GA_PARENT);
10877 ok(test == parent, "wrong parent %p\n", test);
10878 }
10879 test = GetWindow(child1, GW_OWNER);
10880 ok(!test, "wrong owner %p\n", test);
10881
10882 /* test owner/parent of child2 */
10883 test = GetParent(child2);
10884 ok(test == parent, "wrong parent %p\n", test);
10885 ok(IsChild(parent, child2), "wrong parent/child %p/%p\n", parent, child2);
10886 if(pGetAncestor) {
10887 test = pGetAncestor(child2, GA_PARENT);
10888 ok(test == parent, "wrong parent %p\n", test);
10889 }
10890 test = GetWindow(child2, GW_OWNER);
10891 ok(!test, "wrong owner %p\n", test);
10892
10893 /* test owner/parent of child3 */
10894 test = GetParent(child3);
10895 ok(test == child1, "wrong parent %p\n", test);
10896 ok(IsChild(parent, child3), "wrong parent/child %p/%p\n", parent, child3);
10897 if(pGetAncestor) {
10898 test = pGetAncestor(child3, GA_PARENT);
10899 ok(test == child1, "wrong parent %p\n", test);
10900 }
10901 test = GetWindow(child3, GW_OWNER);
10902 ok(!test, "wrong owner %p\n", test);
10903
10904 /* test owner/parent of child4 */
10905 test = GetParent(child4);
10906 ok(test == parent, "wrong parent %p\n", test);
10907 ok(!IsChild(parent, child4), "wrong parent/child %p/%p\n", parent, child4);
10908 if(pGetAncestor) {
10909 test = pGetAncestor(child4, GA_PARENT);
10910 ok(test == GetDesktopWindow(), "wrong parent %p\n", test);
10911 }
10912 test = GetWindow(child4, GW_OWNER);
10913 ok(test == parent, "wrong owner %p\n", test);
10914
10915 flush_sequence();
10916
10917 trace("parent %p, child1 %p, child2 %p, child3 %p, child4 %p\n",
10918 parent, child1, child2, child3, child4);
10919
10920 SetCapture(child4);
10921 test = GetCapture();
10922 ok(test == child4, "wrong capture window %p\n", test);
10923
10924 test_DestroyWindow_flag = TRUE;
10925 ret = DestroyWindow(parent);
10926 ok( ret, "DestroyWindow() error %d\n", GetLastError());
10927 test_DestroyWindow_flag = FALSE;
10928 ok_sequence(destroy_window_with_children, "destroy window with children", FALSE);
10929
10930 ok(!IsWindow(parent), "parent still exists\n");
10931 ok(!IsWindow(child1), "child1 still exists\n");
10932 ok(!IsWindow(child2), "child2 still exists\n");
10933 ok(!IsWindow(child3), "child3 still exists\n");
10934 ok(!IsWindow(child4), "child4 still exists\n");
10935
10936 test = GetCapture();
10937 ok(!test, "wrong capture window %p\n", test);
10938 }
10939
10940
10941 static const struct message WmDispatchPaint[] = {
10942 { WM_NCPAINT, sent },
10943 { WM_GETTEXT, sent|defwinproc|optional },
10944 { WM_GETTEXT, sent|defwinproc|optional },
10945 { WM_ERASEBKGND, sent },
10946 { 0 }
10947 };
10948
10949 static LRESULT WINAPI DispatchMessageCheckProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
10950 {
10951 if (message == WM_PAINT) return 0;
10952 return MsgCheckProcA( hwnd, message, wParam, lParam );
10953 }
10954
10955 static void test_DispatchMessage(void)
10956 {
10957 RECT rect;
10958 MSG msg;
10959 int count;
10960 HWND hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
10961 100, 100, 200, 200, 0, 0, 0, NULL);
10962 ShowWindow( hwnd, SW_SHOW );
10963 UpdateWindow( hwnd );
10964 flush_events();
10965 flush_sequence();
10966 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)DispatchMessageCheckProc );
10967
10968 SetRect( &rect, -5, -5, 5, 5 );
10969 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
10970 count = 0;
10971 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
10972 {
10973 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
10974 else
10975 {
10976 flush_sequence();
10977 DispatchMessageA( &msg );
10978 /* DispatchMessage will send WM_NCPAINT if non client area is still invalid after WM_PAINT */
10979 if (!count) ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
10980 else ok_sequence( WmEmptySeq, "WmEmpty", FALSE );
10981 if (++count > 10) break;
10982 }
10983 }
10984 ok( msg.message == WM_PAINT && count > 10, "WM_PAINT messages stopped\n" );
10985
10986 trace("now without DispatchMessage\n");
10987 flush_sequence();
10988 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
10989 count = 0;
10990 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
10991 {
10992 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
10993 else
10994 {
10995 HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
10996 flush_sequence();
10997 /* this will send WM_NCCPAINT just like DispatchMessage does */
10998 GetUpdateRgn( hwnd, hrgn, TRUE );
10999 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11000 DeleteObject( hrgn );
11001 GetClientRect( hwnd, &rect );
11002 ValidateRect( hwnd, &rect ); /* this will stop WM_PAINTs */
11003 ok( !count, "Got multiple WM_PAINTs\n" );
11004 if (++count > 10) break;
11005 }
11006 }
11007
11008 flush_sequence();
11009 RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_FRAME );
11010 count = 0;
11011 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE ))
11012 {
11013 if (msg.message != WM_PAINT) DispatchMessageA( &msg );
11014 else
11015 {
11016 HDC hdc;
11017
11018 flush_sequence();
11019 hdc = BeginPaint( hwnd, NULL );
11020 ok( !hdc, "got valid hdc %p from BeginPaint\n", hdc );
11021 ok( !EndPaint( hwnd, NULL ), "EndPaint succeeded\n" );
11022 ok_sequence( WmDispatchPaint, "WmDispatchPaint", FALSE );
11023 ok( !count, "Got multiple WM_PAINTs\n" );
11024 if (++count > 10) break;
11025 }
11026 }
11027 DestroyWindow(hwnd);
11028 }
11029
11030
11031 static const struct message WmUser[] = {
11032 { WM_USER, sent },
11033 { 0 }
11034 };
11035
11036 struct sendmsg_info
11037 {
11038 HWND hwnd;
11039 DWORD timeout;
11040 DWORD ret;
11041 };
11042
11043 static DWORD CALLBACK send_msg_thread( LPVOID arg )
11044 {
11045 struct sendmsg_info *info = arg;
11046 SetLastError( 0xdeadbeef );
11047 info->ret = SendMessageTimeoutA( info->hwnd, WM_USER, 0, 0, 0, info->timeout, NULL );
11048 if (!info->ret) ok( GetLastError() == ERROR_TIMEOUT ||
11049 broken(GetLastError() == 0), /* win9x */
11050 "unexpected error %d\n", GetLastError());
11051 return 0;
11052 }
11053
11054 static void wait_for_thread( HANDLE thread )
11055 {
11056 while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_SENDMESSAGE) != WAIT_OBJECT_0)
11057 {
11058 MSG msg;
11059 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA(&msg);
11060 }
11061 }
11062
11063 static LRESULT WINAPI send_msg_delay_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11064 {
11065 if (message == WM_USER) Sleep(200);
11066 return MsgCheckProcA( hwnd, message, wParam, lParam );
11067 }
11068
11069 static void test_SendMessageTimeout(void)
11070 {
11071 HANDLE thread;
11072 struct sendmsg_info info;
11073 DWORD tid;
11074 BOOL is_win9x;
11075
11076 info.hwnd = CreateWindowA( "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11077 100, 100, 200, 200, 0, 0, 0, NULL);
11078 flush_events();
11079 flush_sequence();
11080
11081 info.timeout = 1000;
11082 info.ret = 0xdeadbeef;
11083 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11084 wait_for_thread( thread );
11085 CloseHandle( thread );
11086 ok( info.ret == 1, "SendMessageTimeout failed\n" );
11087 ok_sequence( WmUser, "WmUser", FALSE );
11088
11089 info.timeout = 1;
11090 info.ret = 0xdeadbeef;
11091 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11092 Sleep(100); /* SendMessageTimeout should time out here */
11093 wait_for_thread( thread );
11094 CloseHandle( thread );
11095 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
11096 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11097
11098 /* 0 means infinite timeout (but not on win9x) */
11099 info.timeout = 0;
11100 info.ret = 0xdeadbeef;
11101 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11102 Sleep(100);
11103 wait_for_thread( thread );
11104 CloseHandle( thread );
11105 is_win9x = !info.ret;
11106 if (is_win9x) ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11107 else ok_sequence( WmUser, "WmUser", FALSE );
11108
11109 /* timeout is treated as signed despite the prototype (but not on win9x) */
11110 info.timeout = 0x7fffffff;
11111 info.ret = 0xdeadbeef;
11112 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11113 Sleep(100);
11114 wait_for_thread( thread );
11115 CloseHandle( thread );
11116 ok( info.ret == 1, "SendMessageTimeout failed\n" );
11117 ok_sequence( WmUser, "WmUser", FALSE );
11118
11119 info.timeout = 0x80000000;
11120 info.ret = 0xdeadbeef;
11121 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11122 Sleep(100);
11123 wait_for_thread( thread );
11124 CloseHandle( thread );
11125 if (is_win9x)
11126 {
11127 ok( info.ret == 1, "SendMessageTimeout failed\n" );
11128 ok_sequence( WmUser, "WmUser", FALSE );
11129 }
11130 else
11131 {
11132 ok( info.ret == 0, "SendMessageTimeout succeeded\n" );
11133 ok_sequence( WmEmptySeq, "WmEmptySeq", FALSE );
11134 }
11135
11136 /* now check for timeout during message processing */
11137 SetWindowLongPtrA( info.hwnd, GWLP_WNDPROC, (LONG_PTR)send_msg_delay_proc );
11138 info.timeout = 100;
11139 info.ret = 0xdeadbeef;
11140 thread = CreateThread( NULL, 0, send_msg_thread, &info, 0, &tid );
11141 wait_for_thread( thread );
11142 CloseHandle( thread );
11143 /* we should time out but still get the message */
11144 ok( info.ret == 0, "SendMessageTimeout failed\n" );
11145 ok_sequence( WmUser, "WmUser", FALSE );
11146
11147 DestroyWindow( info.hwnd );
11148 }
11149
11150
11151 /****************** edit message test *************************/
11152 #define ID_EDIT 0x1234
11153 static const struct message sl_edit_setfocus[] =
11154 {
11155 { HCBT_SETFOCUS, hook },
11156 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11157 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11158 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11159 { WM_SETFOCUS, sent|wparam, 0 },
11160 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11161 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 15 },
11162 { WM_CTLCOLOREDIT, sent|parent },
11163 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11164 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11165 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11166 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11167 { 0 }
11168 };
11169 static const struct message sl_edit_invisible[] =
11170 {
11171 { HCBT_SETFOCUS, hook },
11172 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11173 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11174 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11175 { WM_KILLFOCUS, sent|parent },
11176 { WM_SETFOCUS, sent },
11177 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11178 { 0 }
11179 };
11180 static const struct message ml_edit_setfocus[] =
11181 {
11182 { HCBT_SETFOCUS, hook },
11183 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
11184 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11185 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11186 { WM_SETFOCUS, sent|wparam, 0 },
11187 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11188 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11189 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11190 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11191 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11192 { 0 }
11193 };
11194 static const struct message sl_edit_killfocus[] =
11195 {
11196 { HCBT_SETFOCUS, hook },
11197 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11198 { WM_KILLFOCUS, sent|wparam, 0 },
11199 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11200 { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11201 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_KILLFOCUS) },
11202 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
11203 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
11204 { 0 }
11205 };
11206 static const struct message sl_edit_lbutton_dblclk[] =
11207 {
11208 { WM_LBUTTONDBLCLK, sent },
11209 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11210 { 0 }
11211 };
11212 static const struct message sl_edit_lbutton_down[] =
11213 {
11214 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
11215 { HCBT_SETFOCUS, hook },
11216 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11217 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11218 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11219 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
11220 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11221 { WM_CTLCOLOREDIT, sent|parent },
11222 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11223 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11224 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11225 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11226 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11227 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11228 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11229 { WM_CTLCOLOREDIT, sent|parent|optional },
11230 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11231 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11232 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11233 { 0 }
11234 };
11235 static const struct message ml_edit_lbutton_down[] =
11236 {
11237 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, 0 },
11238 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
11239 { HCBT_SETFOCUS, hook },
11240 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
11241 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
11242 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
11243 { WM_SETFOCUS, sent|wparam|defwinproc, 0 },
11244 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
11245 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
11246 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11247 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11248 { WM_COMMAND, sent|parent|wparam, MAKEWPARAM(ID_EDIT, EN_SETFOCUS) },
11249 { 0 }
11250 };
11251 static const struct message sl_edit_lbutton_up[] =
11252 {
11253 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11254 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11255 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11256 { WM_CAPTURECHANGED, sent|defwinproc },
11257 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
11258 { 0 }
11259 };
11260 static const struct message ml_edit_lbutton_up[] =
11261 {
11262 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
11263 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
11264 { WM_CAPTURECHANGED, sent|defwinproc },
11265 { 0 }
11266 };
11267
11268 static WNDPROC old_edit_proc;
11269
11270 static LRESULT CALLBACK edit_hook_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
11271 {
11272 static LONG defwndproc_counter = 0;
11273 LRESULT ret;
11274 struct recvd_message msg;
11275
11276 if (ignore_message( message )) return 0;
11277
11278 msg.hwnd = hwnd;
11279 msg.message = message;
11280 msg.flags = sent|wparam|lparam;
11281 if (defwndproc_counter) msg.flags |= defwinproc;
11282 msg.wParam = wParam;
11283 msg.lParam = lParam;
11284 msg.descr = "edit";
11285 add_message(&msg);
11286
11287 defwndproc_counter++;
11288 ret = CallWindowProcA(old_edit_proc, hwnd, message, wParam, lParam);
11289 defwndproc_counter--;
11290
11291 return ret;
11292 }
11293
11294 static void subclass_edit(void)
11295 {
11296 WNDCLASSA cls;
11297
11298 if (!GetClassInfoA(0, "edit", &cls)) assert(0);
11299
11300 old_edit_proc = cls.lpfnWndProc;
11301
11302 cls.hInstance = GetModuleHandleA(NULL);
11303 cls.lpfnWndProc = edit_hook_proc;
11304 cls.lpszClassName = "my_edit_class";
11305 UnregisterClassA(cls.lpszClassName, cls.hInstance);
11306 if (!RegisterClassA(&cls)) assert(0);
11307 }
11308
11309 static void test_edit_messages(void)
11310 {
11311 HWND hwnd, parent;
11312 DWORD dlg_code;
11313
11314 subclass_edit();
11315 log_all_parent_messages++;
11316
11317 parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
11318 100, 100, 200, 200, 0, 0, 0, NULL);
11319 ok (parent != 0, "Failed to create parent window\n");
11320
11321 /* test single line edit */
11322 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD,
11323 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
11324 ok(hwnd != 0, "Failed to create edit window\n");
11325
11326 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
11327 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS), "wrong dlg_code %08x\n", dlg_code);
11328
11329 flush_sequence();
11330 SetFocus(hwnd);
11331 ok_sequence(sl_edit_invisible, "SetFocus(hwnd) on an invisible edit", FALSE);
11332
11333 ShowWindow(hwnd, SW_SHOW);
11334 UpdateWindow(hwnd);
11335 SetFocus(0);
11336 flush_sequence();
11337
11338 SetFocus(hwnd);
11339 ok_sequence(sl_edit_setfocus, "SetFocus(hwnd) on an edit", FALSE);
11340
11341 SetFocus(0);
11342 ok_sequence(sl_edit_killfocus, "SetFocus(0) on an edit", FALSE);
11343
11344 SetFocus(0);
11345 ReleaseCapture();
11346 flush_sequence();
11347
11348 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
11349 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on an edit", FALSE);
11350
11351 SetFocus(0);
11352 ReleaseCapture();
11353 flush_sequence();
11354
11355 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
11356 ok_sequence(sl_edit_lbutton_down, "WM_LBUTTONDOWN on an edit", FALSE);
11357
11358 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
11359 ok_sequence(sl_edit_lbutton_up, "WM_LBUTTONUP on an edit", FALSE);
11360
11361 DestroyWindow(hwnd);
11362
11363 /* test multiline edit */
11364 hwnd = CreateWindowExA(0, "my_edit_class", "test", WS_CHILD | ES_MULTILINE,
11365 0, 0, 80, 20, parent, (HMENU)ID_EDIT, 0, NULL);
11366 ok(hwnd != 0, "Failed to create edit window\n");
11367
11368 dlg_code = SendMessageA(hwnd, WM_GETDLGCODE, 0, 0);
11369 ok(dlg_code == (DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTARROWS|DLGC_WANTALLKEYS),
11370 "wrong dlg_code %08x\n", dlg_code);
11371
11372 ShowWindow(hwnd, SW_SHOW);
11373 UpdateWindow(hwnd);
11374 SetFocus(0);
11375 flush_sequence();
11376
11377 SetFocus(hwnd);
11378 ok_sequence(ml_edit_setfocus, "SetFocus(hwnd) on multiline edit", FALSE);
11379
11380 SetFocus(0);
11381 ok_sequence(sl_edit_killfocus, "SetFocus(0) on multiline edit", FALSE);
11382
11383 SetFocus(0);
11384 ReleaseCapture();
11385 flush_sequence();
11386
11387 SendMessageA(hwnd, WM_LBUTTONDBLCLK, 0, 0);
11388 ok_sequence(sl_edit_lbutton_dblclk, "WM_LBUTTONDBLCLK on multiline edit", FALSE);
11389
11390 SetFocus(0);
11391 ReleaseCapture();
11392 flush_sequence();
11393
11394 SendMessageA(hwnd, WM_LBUTTONDOWN, 0, 0);
11395 ok_sequence(ml_edit_lbutton_down, "WM_LBUTTONDOWN on multiline edit", FALSE);
11396
11397 SendMessageA(hwnd, WM_LBUTTONUP, 0, 0);
11398 ok_sequence(ml_edit_lbutton_up, "WM_LBUTTONUP on multiline edit", FALSE);
11399
11400 DestroyWindow(hwnd);
11401 DestroyWindow(parent);
11402
11403 log_all_parent_messages--;
11404 }
11405
11406 /**************************** End of Edit test ******************************/
11407
11408 static const struct message WmKeyDownSkippedSeq[] =
11409 {
11410 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 1 }, /* XP */
11411 { 0 }
11412 };
11413 static const struct message WmKeyDownWasDownSkippedSeq[] =
11414 {
11415 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0x40000001 }, /* XP */
11416 { 0 }
11417 };
11418 static const struct message WmKeyUpSkippedSeq[] =
11419 {
11420 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
11421 { 0 }
11422 };
11423 static const struct message WmUserKeyUpSkippedSeq[] =
11424 {
11425 { WM_USER, sent },
11426 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'N', 0xc0000001 }, /* XP */
11427 { 0 }
11428 };
11429
11430 #define EV_STOP 0
11431 #define EV_SENDMSG 1
11432 #define EV_ACK 2
11433
11434 struct peekmsg_info
11435 {
11436 HWND hwnd;
11437 HANDLE hevent[3]; /* 0 - start/stop, 1 - SendMessage, 2 - ack */
11438 };
11439
11440 static DWORD CALLBACK send_msg_thread_2(void *param)
11441 {
11442 DWORD ret;
11443 struct peekmsg_info *info = param;
11444
11445 trace("thread: looping\n");
11446 SetEvent(info->hevent[EV_ACK]);
11447
11448 while (1)
11449 {
11450 ret = WaitForMultipleObjects(2, info->hevent, FALSE, INFINITE);
11451
11452 switch (ret)
11453 {
11454 case WAIT_OBJECT_0 + EV_STOP:
11455 trace("thread: exiting\n");
11456 return 0;
11457
11458 case WAIT_OBJECT_0 + EV_SENDMSG:
11459 trace("thread: sending message\n");
11460 ret = SendNotifyMessageA(info->hwnd, WM_USER, 0, 0);
11461 ok(ret, "SendNotifyMessageA failed error %u\n", GetLastError());
11462 SetEvent(info->hevent[EV_ACK]);
11463 break;
11464
11465 default:
11466 trace("unexpected return: %04x\n", ret);
11467 assert(0);
11468 break;
11469 }
11470 }
11471 return 0;
11472 }
11473
11474 static void test_PeekMessage(void)
11475 {
11476 MSG msg;
11477 HANDLE hthread;
11478 DWORD tid, qstatus;
11479 UINT qs_all_input = QS_ALLINPUT;
11480 UINT qs_input = QS_INPUT;
11481 BOOL ret;
11482 struct peekmsg_info info;
11483
11484 info.hwnd = CreateWindowA("TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
11485 100, 100, 200, 200, 0, 0, 0, NULL);
11486 assert(info.hwnd);
11487 ShowWindow(info.hwnd, SW_SHOW);
11488 UpdateWindow(info.hwnd);
11489 SetFocus(info.hwnd);
11490
11491 info.hevent[EV_STOP] = CreateEventA(NULL, 0, 0, NULL);
11492 info.hevent[EV_SENDMSG] = CreateEventA(NULL, 0, 0, NULL);
11493 info.hevent[EV_ACK] = CreateEventA(NULL, 0, 0, NULL);
11494
11495 hthread = CreateThread(NULL, 0, send_msg_thread_2, &info, 0, &tid);
11496 WaitForSingleObject(info.hevent[EV_ACK], 10000);
11497
11498 flush_events();
11499 flush_sequence();
11500
11501 SetLastError(0xdeadbeef);
11502 qstatus = GetQueueStatus(qs_all_input);
11503 if (GetLastError() == ERROR_INVALID_FLAGS)
11504 {
11505 trace("QS_RAWINPUT not supported on this platform\n");
11506 qs_all_input &= ~QS_RAWINPUT;
11507 qs_input &= ~QS_RAWINPUT;
11508 }
11509 if (qstatus & QS_POSTMESSAGE)
11510 {
11511 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) /* nothing */ ;
11512 qstatus = GetQueueStatus(qs_all_input);
11513 }
11514 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11515
11516 trace("signalling to send message\n");
11517 SetEvent(info.hevent[EV_SENDMSG]);
11518 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11519
11520 /* pass invalid QS_xxxx flags */
11521 SetLastError(0xdeadbeef);
11522 qstatus = GetQueueStatus(0xffffffff);
11523 ok(qstatus == 0 || broken(qstatus) /* win9x */, "GetQueueStatus should fail: %08x\n", qstatus);
11524 if (!qstatus)
11525 {
11526 ok(GetLastError() == ERROR_INVALID_FLAGS, "wrong error %d\n", GetLastError());
11527 qstatus = GetQueueStatus(qs_all_input);
11528 }
11529 qstatus &= ~MAKELONG( 0x4000, 0x4000 ); /* sometimes set on Win95 */
11530 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE),
11531 "wrong qstatus %08x\n", qstatus);
11532
11533 msg.message = 0;
11534 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11535 ok(!ret,
11536 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11537 msg.message);
11538 ok_sequence(WmUser, "WmUser", FALSE);
11539
11540 qstatus = GetQueueStatus(qs_all_input);
11541 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11542
11543 keybd_event('N', 0, 0, 0);
11544 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
11545 qstatus = GetQueueStatus(qs_all_input);
11546 if (!(qstatus & MAKELONG(QS_KEY, QS_KEY)))
11547 {
11548 skip( "queuing key events not supported\n" );
11549 goto done;
11550 }
11551 ok(qstatus == MAKELONG(QS_KEY, QS_KEY) ||
11552 /* keybd_event seems to trigger a sent message on NT4 */
11553 qstatus == MAKELONG(QS_KEY|QS_SENDMESSAGE, QS_KEY|QS_SENDMESSAGE),
11554 "wrong qstatus %08x\n", qstatus);
11555
11556 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11557 qstatus = GetQueueStatus(qs_all_input);
11558 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY) ||
11559 qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
11560 "wrong qstatus %08x\n", qstatus);
11561
11562 InvalidateRect(info.hwnd, NULL, FALSE);
11563 qstatus = GetQueueStatus(qs_all_input);
11564 ok(qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY) ||
11565 qstatus == MAKELONG(QS_PAINT, QS_PAINT|QS_POSTMESSAGE|QS_KEY|QS_SENDMESSAGE),
11566 "wrong qstatus %08x\n", qstatus);
11567
11568 trace("signalling to send message\n");
11569 SetEvent(info.hevent[EV_SENDMSG]);
11570 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11571
11572 qstatus = GetQueueStatus(qs_all_input);
11573 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11574 "wrong qstatus %08x\n", qstatus);
11575
11576 msg.message = 0;
11577 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (qs_input << 16));
11578 if (ret && msg.message == WM_CHAR)
11579 {
11580 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
11581 goto done;
11582 }
11583 ok(!ret,
11584 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11585 msg.message);
11586 if (!sequence_cnt) /* nt4 doesn't fetch anything with PM_QS_* flags */
11587 {
11588 win_skip( "PM_QS_* flags not supported in PeekMessage\n" );
11589 goto done;
11590 }
11591 ok_sequence(WmUser, "WmUser", FALSE);
11592
11593 qstatus = GetQueueStatus(qs_all_input);
11594 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11595 "wrong qstatus %08x\n", qstatus);
11596
11597 trace("signalling to send message\n");
11598 SetEvent(info.hevent[EV_SENDMSG]);
11599 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11600
11601 qstatus = GetQueueStatus(qs_all_input);
11602 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11603 "wrong qstatus %08x\n", qstatus);
11604
11605 msg.message = 0;
11606 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE );
11607 ok(!ret,
11608 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11609 msg.message);
11610 ok_sequence(WmUser, "WmUser", FALSE);
11611
11612 qstatus = GetQueueStatus(qs_all_input);
11613 ok(qstatus == MAKELONG(0, QS_PAINT|QS_POSTMESSAGE|QS_KEY),
11614 "wrong qstatus %08x\n", qstatus);
11615
11616 msg.message = 0;
11617 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
11618 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11619 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11620 ret, msg.message, msg.wParam);
11621 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11622
11623 qstatus = GetQueueStatus(qs_all_input);
11624 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
11625 "wrong qstatus %08x\n", qstatus);
11626
11627 msg.message = 0;
11628 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_POSTMESSAGE);
11629 ok(!ret,
11630 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11631 msg.message);
11632 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11633
11634 qstatus = GetQueueStatus(qs_all_input);
11635 ok(qstatus == MAKELONG(0, QS_PAINT|QS_KEY),
11636 "wrong qstatus %08x\n", qstatus);
11637
11638 msg.message = 0;
11639 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
11640 ok(ret && msg.message == WM_PAINT,
11641 "got %d and %04x instead of TRUE and WM_PAINT\n", ret, msg.message);
11642 DispatchMessageA(&msg);
11643 ok_sequence(WmPaint, "WmPaint", FALSE);
11644
11645 qstatus = GetQueueStatus(qs_all_input);
11646 ok(qstatus == MAKELONG(0, QS_KEY),
11647 "wrong qstatus %08x\n", qstatus);
11648
11649 msg.message = 0;
11650 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_PAINT);
11651 ok(!ret,
11652 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11653 msg.message);
11654 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11655
11656 qstatus = GetQueueStatus(qs_all_input);
11657 ok(qstatus == MAKELONG(0, QS_KEY),
11658 "wrong qstatus %08x\n", qstatus);
11659
11660 trace("signalling to send message\n");
11661 SetEvent(info.hevent[EV_SENDMSG]);
11662 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11663
11664 qstatus = GetQueueStatus(qs_all_input);
11665 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_KEY),
11666 "wrong qstatus %08x\n", qstatus);
11667
11668 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11669
11670 qstatus = GetQueueStatus(qs_all_input);
11671 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
11672 "wrong qstatus %08x\n", qstatus);
11673
11674 msg.message = 0;
11675 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
11676 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11677 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11678 ret, msg.message, msg.wParam);
11679 ok_sequence(WmUser, "WmUser", FALSE);
11680
11681 qstatus = GetQueueStatus(qs_all_input);
11682 ok(qstatus == MAKELONG(0, QS_KEY),
11683 "wrong qstatus %08x\n", qstatus);
11684
11685 msg.message = 0;
11686 ret = PeekMessageA(&msg, 0, WM_CHAR, WM_CHAR, PM_REMOVE);
11687 ok(!ret,
11688 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11689 msg.message);
11690 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11691
11692 qstatus = GetQueueStatus(qs_all_input);
11693 ok(qstatus == MAKELONG(0, QS_KEY),
11694 "wrong qstatus %08x\n", qstatus);
11695
11696 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11697
11698 qstatus = GetQueueStatus(qs_all_input);
11699 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY),
11700 "wrong qstatus %08x\n", qstatus);
11701
11702 trace("signalling to send message\n");
11703 SetEvent(info.hevent[EV_SENDMSG]);
11704 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11705
11706 qstatus = GetQueueStatus(qs_all_input);
11707 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
11708 "wrong qstatus %08x\n", qstatus);
11709
11710 msg.message = 0;
11711 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_KEY << 16));
11712 ok(!ret,
11713 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11714 msg.message);
11715 ok_sequence(WmUser, "WmUser", FALSE);
11716
11717 qstatus = GetQueueStatus(qs_all_input);
11718 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
11719 "wrong qstatus %08x\n", qstatus);
11720
11721 msg.message = 0;
11722 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
11723 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
11724 else /* workaround for a missing QS_RAWINPUT support */
11725 ret = PeekMessageA(&msg, 0, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE);
11726 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
11727 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
11728 ret, msg.message, msg.wParam);
11729 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
11730
11731 qstatus = GetQueueStatus(qs_all_input);
11732 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE|QS_KEY),
11733 "wrong qstatus %08x\n", qstatus);
11734
11735 msg.message = 0;
11736 if (qs_all_input & QS_RAWINPUT) /* use QS_RAWINPUT only if supported */
11737 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | (QS_RAWINPUT << 16));
11738 else /* workaround for a missing QS_RAWINPUT support */
11739 ret = PeekMessageA(&msg, 0, WM_KEYUP, WM_KEYUP, PM_REMOVE);
11740 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
11741 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYUP wParam 'N'\n",
11742 ret, msg.message, msg.wParam);
11743 ok_sequence(WmKeyUpSkippedSeq, "WmKeyUpSkippedSeq", FALSE);
11744
11745 qstatus = GetQueueStatus(qs_all_input);
11746 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11747 "wrong qstatus %08x\n", qstatus);
11748
11749 msg.message = 0;
11750 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE);
11751 ok(!ret,
11752 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11753 msg.message);
11754 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11755
11756 qstatus = GetQueueStatus(qs_all_input);
11757 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11758 "wrong qstatus %08x\n", qstatus);
11759
11760 msg.message = 0;
11761 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11762 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11763 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11764 ret, msg.message, msg.wParam);
11765 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11766
11767 qstatus = GetQueueStatus(qs_all_input);
11768 ok(qstatus == 0,
11769 "wrong qstatus %08x\n", qstatus);
11770
11771 msg.message = 0;
11772 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11773 ok(!ret,
11774 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11775 msg.message);
11776 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11777
11778 qstatus = GetQueueStatus(qs_all_input);
11779 ok(qstatus == 0,
11780 "wrong qstatus %08x\n", qstatus);
11781
11782 /* test whether presence of the quit flag in the queue affects
11783 * the queue state
11784 */
11785 PostQuitMessage(0x1234abcd);
11786
11787 qstatus = GetQueueStatus(qs_all_input);
11788 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
11789 "wrong qstatus %08x\n", qstatus);
11790
11791 PostMessageA(info.hwnd, WM_USER, 0, 0);
11792
11793 qstatus = GetQueueStatus(qs_all_input);
11794 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE),
11795 "wrong qstatus %08x\n", qstatus);
11796
11797 msg.message = 0;
11798 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11799 ok(ret && msg.message == WM_USER,
11800 "got %d and %04x instead of TRUE and WM_USER\n", ret, msg.message);
11801 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11802
11803 qstatus = GetQueueStatus(qs_all_input);
11804 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11805 "wrong qstatus %08x\n", qstatus);
11806
11807 msg.message = 0;
11808 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11809 ok(ret && msg.message == WM_QUIT,
11810 "got %d and %04x instead of TRUE and WM_QUIT\n", ret, msg.message);
11811 ok(msg.wParam == 0x1234abcd, "got wParam %08lx instead of 0x1234abcd\n", msg.wParam);
11812 ok(msg.lParam == 0, "got lParam %08lx instead of 0\n", msg.lParam);
11813 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11814
11815 qstatus = GetQueueStatus(qs_all_input);
11816 todo_wine {
11817 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE),
11818 "wrong qstatus %08x\n", qstatus);
11819 }
11820
11821 msg.message = 0;
11822 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
11823 ok(!ret,
11824 "PeekMessageA should have returned FALSE instead of msg %04x\n",
11825 msg.message);
11826 ok_sequence(WmEmptySeq, "WmEmptySeq", FALSE);
11827
11828 qstatus = GetQueueStatus(qs_all_input);
11829 ok(qstatus == 0,
11830 "wrong qstatus %08x\n", qstatus);
11831
11832 /* some GetMessage tests */
11833
11834 keybd_event('N', 0, 0, 0);
11835 qstatus = GetQueueStatus(qs_all_input);
11836 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
11837
11838 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11839 qstatus = GetQueueStatus(qs_all_input);
11840 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
11841
11842 if (qstatus)
11843 {
11844 ret = GetMessageA( &msg, 0, 0, 0 );
11845 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11846 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11847 ret, msg.message, msg.wParam);
11848 qstatus = GetQueueStatus(qs_all_input);
11849 ok(qstatus == MAKELONG(0, QS_KEY), "wrong qstatus %08x\n", qstatus);
11850 }
11851
11852 if (qstatus)
11853 {
11854 ret = GetMessageA( &msg, 0, 0, 0 );
11855 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
11856 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
11857 ret, msg.message, msg.wParam);
11858 ok_sequence(WmKeyDownSkippedSeq, "WmKeyDownSkippedSeq", FALSE);
11859 qstatus = GetQueueStatus(qs_all_input);
11860 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11861 }
11862
11863 keybd_event('N', 0, 0, 0);
11864 qstatus = GetQueueStatus(qs_all_input);
11865 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
11866
11867 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11868 qstatus = GetQueueStatus(qs_all_input);
11869 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
11870
11871 if (qstatus & (QS_KEY << 16))
11872 {
11873 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
11874 ok(ret && msg.message == WM_KEYDOWN && msg.wParam == 'N',
11875 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
11876 ret, msg.message, msg.wParam);
11877 ok_sequence(WmKeyDownWasDownSkippedSeq, "WmKeyDownWasDownSkippedSeq", FALSE);
11878 qstatus = GetQueueStatus(qs_all_input);
11879 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
11880 }
11881
11882 if (qstatus)
11883 {
11884 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
11885 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11886 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11887 ret, msg.message, msg.wParam);
11888 qstatus = GetQueueStatus(qs_all_input);
11889 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11890 }
11891
11892 keybd_event('N', 0, KEYEVENTF_KEYUP, 0);
11893 qstatus = GetQueueStatus(qs_all_input);
11894 ok(qstatus == MAKELONG(QS_KEY, QS_KEY), "wrong qstatus %08x\n", qstatus);
11895
11896 PostMessageA(info.hwnd, WM_CHAR, 'z', 0);
11897 qstatus = GetQueueStatus(qs_all_input);
11898 ok(qstatus == MAKELONG(QS_POSTMESSAGE, QS_POSTMESSAGE|QS_KEY), "wrong qstatus %08x\n", qstatus);
11899
11900 trace("signalling to send message\n");
11901 SetEvent(info.hevent[EV_SENDMSG]);
11902 WaitForSingleObject(info.hevent[EV_ACK], INFINITE);
11903 qstatus = GetQueueStatus(qs_all_input);
11904 ok(qstatus == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE|QS_KEY),
11905 "wrong qstatus %08x\n", qstatus);
11906
11907 if (qstatus & (QS_KEY << 16))
11908 {
11909 ret = GetMessageA( &msg, 0, WM_KEYDOWN, WM_KEYUP );
11910 ok(ret && msg.message == WM_KEYUP && msg.wParam == 'N',
11911 "got %d and %04x wParam %08lx instead of TRUE and WM_KEYDOWN wParam 'N'\n",
11912 ret, msg.message, msg.wParam);
11913 ok_sequence(WmUserKeyUpSkippedSeq, "WmUserKeyUpSkippedSeq", FALSE);
11914 qstatus = GetQueueStatus(qs_all_input);
11915 ok(qstatus == MAKELONG(0, QS_POSTMESSAGE), "wrong qstatus %08x\n", qstatus);
11916 }
11917
11918 if (qstatus)
11919 {
11920 ret = GetMessageA( &msg, 0, WM_CHAR, WM_CHAR );
11921 ok(ret && msg.message == WM_CHAR && msg.wParam == 'z',
11922 "got %d and %04x wParam %08lx instead of TRUE and WM_CHAR wParam 'z'\n",
11923 ret, msg.message, msg.wParam);
11924 qstatus = GetQueueStatus(qs_all_input);
11925 ok(qstatus == 0, "wrong qstatus %08x\n", qstatus);
11926 }
11927 done:
11928 trace("signalling to exit\n");
11929 SetEvent(info.hevent[EV_STOP]);
11930
11931 WaitForSingleObject(hthread, INFINITE);
11932
11933 CloseHandle(hthread);
11934 CloseHandle(info.hevent[0]);
11935 CloseHandle(info.hevent[1]);
11936 CloseHandle(info.hevent[2]);
11937
11938 DestroyWindow(info.hwnd);
11939 }
11940
11941 static void wait_move_event(HWND hwnd, int x, int y)
11942 {
11943 MSG msg;
11944 DWORD time;
11945 BOOL ret;
11946
11947 time = GetTickCount();
11948 while (GetTickCount() - time < 200) {
11949 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
11950 if (ret && msg.pt.x > x && msg.pt.y > y) break;
11951 if (!ret) MsgWaitForMultipleObjects( 0, NULL, FALSE, GetTickCount() - time, QS_ALLINPUT );
11952 else Sleep( GetTickCount() - time );
11953 }
11954 }
11955
11956 #define STEP 5
11957 static void test_PeekMessage2(void)
11958 {
11959 HWND hwnd;
11960 BOOL ret;
11961 MSG msg;
11962 UINT message;
11963 DWORD time1, time2, time3;
11964 int x1, y1, x2, y2, x3, y3;
11965 POINT pos;
11966
11967 time1 = time2 = time3 = 0;
11968 x1 = y1 = x2 = y2 = x3 = y3 = 0;
11969
11970 /* Initialise window and make sure it is ready for events */
11971 hwnd = CreateWindowA("TestWindowClass", "PeekMessage2", WS_OVERLAPPEDWINDOW,
11972 10, 10, 800, 800, NULL, NULL, NULL, NULL);
11973 assert(hwnd);
11974 trace("Window for test_PeekMessage2 %p\n", hwnd);
11975 ShowWindow(hwnd, SW_SHOW);
11976 UpdateWindow(hwnd);
11977 SetFocus(hwnd);
11978 GetCursorPos(&pos);
11979 SetCursorPos(100, 100);
11980 mouse_event(MOUSEEVENTF_MOVE, -STEP, -STEP, 0, 0);
11981 flush_events();
11982
11983 /* Do initial mousemove, wait until we can see it
11984 and then do our test peek with PM_NOREMOVE. */
11985 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
11986 wait_move_event(hwnd, 100-STEP, 100-STEP);
11987
11988 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
11989 if (!ret)
11990 {
11991 skip( "queuing mouse events not supported\n" );
11992 goto done;
11993 }
11994 else
11995 {
11996 trace("1st move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
11997 message = msg.message;
11998 time1 = msg.time;
11999 x1 = msg.pt.x;
12000 y1 = msg.pt.y;
12001 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12002 }
12003
12004 /* Allow time to advance a bit, and then simulate the user moving their
12005 * mouse around. After that we peek again with PM_NOREMOVE.
12006 * Although the previous mousemove message was never removed, the
12007 * mousemove we now peek should reflect the recent mouse movements
12008 * because the input queue will merge the move events. */
12009 Sleep(100);
12010 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
12011 wait_move_event(hwnd, x1, y1);
12012
12013 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12014 ok(ret, "no message available\n");
12015 if (ret) {
12016 trace("2nd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
12017 message = msg.message;
12018 time2 = msg.time;
12019 x2 = msg.pt.x;
12020 y2 = msg.pt.y;
12021 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12022 ok(time2 > time1, "message time not advanced: %x %x\n", time1, time2);
12023 ok(x2 != x1 && y2 != y1, "coords not changed: (%d %d) (%d %d)\n", x1, y1, x2, y2);
12024 }
12025
12026 /* Have another go, to drive the point home */
12027 Sleep(100);
12028 mouse_event(MOUSEEVENTF_MOVE, STEP, STEP, 0, 0);
12029 wait_move_event(hwnd, x2, y2);
12030
12031 ret = PeekMessageA(&msg, hwnd, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_NOREMOVE);
12032 ok(ret, "no message available\n");
12033 if (ret) {
12034 trace("3rd move event: %04x %x %d %d\n", msg.message, msg.time, msg.pt.x, msg.pt.y);
12035 message = msg.message;
12036 time3 = msg.time;
12037 x3 = msg.pt.x;
12038 y3 = msg.pt.y;
12039 ok(message == WM_MOUSEMOVE, "message not WM_MOUSEMOVE, %04x instead\n", message);
12040 ok(time3 > time2, "message time not advanced: %x %x\n", time2, time3);
12041 ok(x3 != x2 && y3 != y2, "coords not changed: (%d %d) (%d %d)\n", x2, y2, x3, y3);
12042 }
12043
12044 done:
12045 DestroyWindow(hwnd);
12046 SetCursorPos(pos.x, pos.y);
12047 flush_events();
12048 }
12049
12050 static void test_PeekMessage3(void)
12051 {
12052 HWND hwnd;
12053 BOOL ret;
12054 MSG msg;
12055
12056 hwnd = CreateWindowA("TestWindowClass", "PeekMessage3", WS_OVERLAPPEDWINDOW,
12057 10, 10, 800, 800, NULL, NULL, NULL, NULL);
12058 ok(hwnd != NULL, "expected hwnd != NULL\n");
12059 flush_events();
12060
12061 /* GetMessage() and PeekMessage(..., PM_REMOVE) should prefer messages which
12062 * were already seen. */
12063
12064 SetTimer(hwnd, 1, 0, NULL);
12065 while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE));
12066 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12067 PostMessageA(hwnd, WM_USER, 0, 0);
12068 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12069 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12070 ret = GetMessageA(&msg, NULL, 0, 0);
12071 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12072 ret = GetMessageA(&msg, NULL, 0, 0);
12073 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12074 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12075 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12076
12077 SetTimer(hwnd, 1, 0, NULL);
12078 while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE));
12079 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12080 PostMessageA(hwnd, WM_USER, 0, 0);
12081 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12082 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12083 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12084 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12085 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12086 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12087
12088 /* It doesn't matter if a message range is specified or not. */
12089
12090 SetTimer(hwnd, 1, 0, NULL);
12091 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12092 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12093 PostMessageA(hwnd, WM_USER, 0, 0);
12094 ret = GetMessageA(&msg, NULL, 0, 0);
12095 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12096 ret = GetMessageA(&msg, NULL, 0, 0);
12097 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12098 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12099 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12100
12101 /* But not if the post messages were added before the PeekMessage() call. */
12102
12103 PostMessageA(hwnd, WM_USER, 0, 0);
12104 SetTimer(hwnd, 1, 0, NULL);
12105 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12106 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12107 ret = GetMessageA(&msg, NULL, 0, 0);
12108 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12109 ret = GetMessageA(&msg, NULL, 0, 0);
12110 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12111 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12112 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12113
12114 /* More complicated test with multiple messages. */
12115
12116 PostMessageA(hwnd, WM_USER, 0, 0);
12117 SetTimer(hwnd, 1, 0, NULL);
12118 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12119 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12120 PostMessageA(hwnd, WM_USER + 1, 0, 0);
12121 ret = GetMessageA(&msg, NULL, 0, 0);
12122 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12123 ret = GetMessageA(&msg, NULL, 0, 0);
12124 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12125 ret = GetMessageA(&msg, NULL, 0, 0);
12126 ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
12127 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12128 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12129
12130 /* Newer messages are still returned when specifying a message range. */
12131
12132 SetTimer(hwnd, 1, 0, NULL);
12133 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12134 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12135 PostMessageA(hwnd, WM_USER + 1, 0, 0);
12136 PostMessageA(hwnd, WM_USER, 0, 0);
12137 ret = PeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
12138 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12139 ret = PeekMessageA(&msg, NULL, WM_USER, WM_USER + 1, PM_NOREMOVE);
12140 ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
12141 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12142 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12143 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12144 ok(ret && msg.message == WM_USER + 1, "msg.message = %u instead of WM_USER + 1\n", msg.message);
12145 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12146 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12147 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12148 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12149
12150 /* Also works for posted messages, but the situation is a bit different,
12151 * because both messages are in the same queue. */
12152
12153 PostMessageA(hwnd, WM_TIMER, 0, 0);
12154 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12155 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12156 PostMessageA(hwnd, WM_USER, 0, 0);
12157 ret = GetMessageA(&msg, NULL, 0, 0);
12158 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12159 ret = GetMessageA(&msg, NULL, 0, 0);
12160 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12161 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12162 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12163
12164 PostMessageA(hwnd, WM_USER, 0, 0);
12165 PostMessageA(hwnd, WM_TIMER, 0, 0);
12166 while (!PeekMessageA(&msg, NULL, WM_TIMER, WM_TIMER, PM_NOREMOVE));
12167 ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12168 ret = GetMessageA(&msg, NULL, 0, 0);
12169 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message);
12170 ret = GetMessageA(&msg, NULL, 0, 0);
12171 ok(ret && msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message);
12172 ret = PeekMessageA(&msg, NULL, 0, 0, 0);
12173 ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret);
12174
12175 DestroyWindow(hwnd);
12176 flush_events();
12177 }
12178
12179 static INT_PTR CALLBACK wm_quit_dlg_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
12180 {
12181 struct recvd_message msg;
12182
12183 if (ignore_message( message )) return 0;
12184
12185 msg.hwnd = hwnd;
12186 msg.message = message;
12187 msg.flags = sent|wparam|lparam;
12188 msg.wParam = wp;
12189 msg.lParam = lp;
12190 msg.descr = "dialog";
12191 add_message(&msg);
12192
12193 switch (message)
12194 {
12195 case WM_INITDIALOG:
12196 PostMessageA(hwnd, WM_QUIT, 0x1234, 0x5678);
12197 PostMessageA(hwnd, WM_USER, 0xdead, 0xbeef);
12198 return 0;
12199
12200 case WM_GETDLGCODE:
12201 return 0;
12202
12203 case WM_USER:
12204 EndDialog(hwnd, 0);
12205 break;
12206 }
12207
12208 return 1;
12209 }
12210
12211 static const struct message WmQuitDialogSeq[] = {
12212 { HCBT_CREATEWND, hook },
12213 { WM_SETFONT, sent },
12214 { WM_INITDIALOG, sent },
12215 { WM_CHANGEUISTATE, sent|optional },
12216 { HCBT_DESTROYWND, hook },
12217 { 0x0090, sent|optional }, /* Vista */
12218 { WM_DESTROY, sent },
12219 { WM_NCDESTROY, sent },
12220 { 0 }
12221 };
12222
12223 static const struct message WmStopQuitSeq[] = {
12224 { WM_DWMNCRENDERINGCHANGED, posted|optional },
12225 { WM_CLOSE, posted },
12226 { WM_QUIT, posted|wparam|lparam, 0x1234, 0 },
12227 { 0 }
12228 };
12229
12230 static void test_quit_message(void)
12231 {
12232 MSG msg;
12233 BOOL ret;
12234
12235 /* test using PostQuitMessage */
12236 flush_events();
12237 PostQuitMessage(0xbeef);
12238
12239 msg.message = 0;
12240 ret = PeekMessageA(&msg, 0, 0, 0, PM_QS_SENDMESSAGE);
12241 ok(!ret, "got %x message\n", msg.message);
12242
12243 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12244 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
12245 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12246 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
12247
12248 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12249 ok(ret, "PostMessage failed with error %d\n", GetLastError());
12250
12251 ret = GetMessageA(&msg, NULL, 0, 0);
12252 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
12253 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
12254
12255 /* note: WM_QUIT message received after WM_USER message */
12256 ret = GetMessageA(&msg, NULL, 0, 0);
12257 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
12258 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12259 ok(msg.wParam == 0xbeef, "wParam was 0x%lx instead of 0xbeef\n", msg.wParam);
12260
12261 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12262 ok( !ret || msg.message != WM_QUIT, "Received WM_QUIT again\n" );
12263
12264 /* now test with PostThreadMessage - different behaviour! */
12265 PostThreadMessageA(GetCurrentThreadId(), WM_QUIT, 0xdead, 0);
12266
12267 ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE);
12268 ok(ret, "PeekMessage failed with error %d\n", GetLastError());
12269 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12270 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
12271
12272 ret = PostThreadMessageA(GetCurrentThreadId(), WM_USER, 0, 0);
12273 ok(ret, "PostMessage failed with error %d\n", GetLastError());
12274
12275 /* note: we receive the WM_QUIT message first this time */
12276 ret = GetMessageA(&msg, NULL, 0, 0);
12277 ok(!ret, "GetMessage return %d with error %d instead of FALSE\n", ret, GetLastError());
12278 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12279 ok(msg.wParam == 0xdead, "wParam was 0x%lx instead of 0xdead\n", msg.wParam);
12280
12281 ret = GetMessageA(&msg, NULL, 0, 0);
12282 ok(ret > 0, "GetMessage failed with error %d\n", GetLastError());
12283 ok(msg.message == WM_USER, "Received message 0x%04x instead of WM_USER\n", msg.message);
12284
12285 flush_events();
12286 flush_sequence();
12287 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, wm_quit_dlg_proc, 0);
12288 ok(ret == 1, "expected 1, got %d\n", ret);
12289 ok_sequence(WmQuitDialogSeq, "WmQuitDialogSeq", FALSE);
12290 memset(&msg, 0xab, sizeof(msg));
12291 ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE);
12292 ok(ret, "PeekMessage failed\n");
12293 ok(msg.message == WM_QUIT, "Received message 0x%04x instead of WM_QUIT\n", msg.message);
12294 ok(msg.wParam == 0x1234, "wParam was 0x%lx instead of 0x1234\n", msg.wParam);
12295 ok(msg.lParam == 0, "lParam was 0x%lx instead of 0\n", msg.lParam);
12296
12297 /* Check what happens to a WM_QUIT message posted to a window that gets
12298 * destroyed.
12299 */
12300 CreateWindowExA(0, "StopQuitClass", "Stop Quit Test", WS_OVERLAPPEDWINDOW,
12301 0, 0, 100, 100, NULL, NULL, NULL, NULL);
12302 flush_sequence();
12303 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12304 {
12305 struct recvd_message rmsg;
12306 rmsg.hwnd = msg.hwnd;
12307 rmsg.message = msg.message;
12308 rmsg.flags = posted|wparam|lparam;
12309 rmsg.wParam = msg.wParam;
12310 rmsg.lParam = msg.lParam;
12311 rmsg.descr = "stop/quit";
12312 if (msg.message == WM_QUIT)
12313 /* The hwnd can only be checked here */
12314 ok(!msg.hwnd, "The WM_QUIT hwnd was %p instead of NULL\n", msg.hwnd);
12315 add_message(&rmsg);
12316 DispatchMessageA(&msg);
12317 }
12318 ok_sequence(WmStopQuitSeq, "WmStopQuitSeq", FALSE);
12319 }
12320
12321 static const struct message WmNotifySeq[] = {
12322 { WM_NOTIFY, sent|wparam|lparam, 0x1234, 0xdeadbeef },
12323 { 0 }
12324 };
12325
12326 static void test_notify_message(void)
12327 {
12328 HWND hwnd;
12329 BOOL ret;
12330 MSG msg;
12331
12332 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
12333 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0, NULL, NULL, 0);
12334 ok(hwnd != 0, "Failed to create window\n");
12335 flush_events();
12336 flush_sequence();
12337
12338 ret = SendNotifyMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12339 ok(ret == TRUE, "SendNotifyMessageA failed with error %u\n", GetLastError());
12340 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12341
12342 ret = SendNotifyMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12343 ok(ret == TRUE, "SendNotifyMessageW failed with error %u\n", GetLastError());
12344 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12345
12346 ret = SendMessageCallbackA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
12347 ok(ret == TRUE, "SendMessageCallbackA failed with error %u\n", GetLastError());
12348 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12349
12350 ret = SendMessageCallbackW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef, NULL, 0);
12351 ok(ret == TRUE, "SendMessageCallbackW failed with error %u\n", GetLastError());
12352 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12353
12354 ret = PostMessageA(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12355 ok(ret == TRUE, "PostMessageA failed with error %u\n", GetLastError());
12356 flush_events();
12357 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12358
12359 ret = PostMessageW(hwnd, WM_NOTIFY, 0x1234, 0xdeadbeef);
12360 ok(ret == TRUE, "PostMessageW failed with error %u\n", GetLastError());
12361 flush_events();
12362 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12363
12364 ret = PostThreadMessageA(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
12365 ok(ret == TRUE, "PostThreadMessageA failed with error %u\n", GetLastError());
12366 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12367 {
12368 msg.hwnd = hwnd;
12369 DispatchMessageA(&msg);
12370 }
12371 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12372
12373 ret = PostThreadMessageW(GetCurrentThreadId(), WM_NOTIFY, 0x1234, 0xdeadbeef);
12374 ok(ret == TRUE, "PostThreadMessageW failed with error %u\n", GetLastError());
12375 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12376 {
12377 msg.hwnd = hwnd;
12378 DispatchMessageA(&msg);
12379 }
12380 ok_sequence(WmNotifySeq, "WmNotifySeq", FALSE);
12381
12382 DestroyWindow(hwnd);
12383 }
12384
12385 static const struct message WmMouseHoverSeq[] = {
12386 { WM_MOUSEACTIVATE, sent|optional }, /* we can get those when moving the mouse in focus-follow-mouse mode under X11 */
12387 { WM_MOUSEACTIVATE, sent|optional },
12388 { WM_TIMER, sent|optional }, /* XP sends it */
12389 { WM_SYSTIMER, sent },
12390 { WM_MOUSEHOVER, sent|wparam, 0 },
12391 { 0 }
12392 };
12393
12394 static void pump_msg_loop_timeout(DWORD timeout, BOOL inject_mouse_move)
12395 {
12396 MSG msg;
12397 DWORD start_ticks, end_ticks;
12398
12399 start_ticks = GetTickCount();
12400 /* add some deviation (50%) to cover not expected delays */
12401 start_ticks += timeout / 2;
12402
12403 do
12404 {
12405 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
12406 {
12407 /* Timer proc messages are not dispatched to the window proc,
12408 * and therefore not logged.
12409 */
12410 if ((msg.message == WM_TIMER || msg.message == WM_SYSTIMER) && msg.hwnd)
12411 {
12412 struct recvd_message s_msg;
12413
12414 s_msg.hwnd = msg.hwnd;
12415 s_msg.message = msg.message;
12416 s_msg.flags = sent|wparam|lparam;
12417 s_msg.wParam = msg.wParam;
12418 s_msg.lParam = msg.lParam;
12419 s_msg.descr = "msg_loop";
12420 add_message(&s_msg);
12421 }
12422 DispatchMessageA(&msg);
12423 }
12424
12425 end_ticks = GetTickCount();
12426
12427 /* inject WM_MOUSEMOVE to see how it changes tracking */
12428 if (inject_mouse_move && start_ticks + timeout / 2 >= end_ticks)
12429 {
12430 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
12431 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
12432
12433 inject_mouse_move = FALSE;
12434 }
12435 } while (start_ticks + timeout >= end_ticks);
12436 }
12437
12438 static void test_TrackMouseEvent(void)
12439 {
12440 TRACKMOUSEEVENT tme;
12441 BOOL ret;
12442 HWND hwnd, hchild;
12443 RECT rc_parent, rc_child;
12444 UINT default_hover_time, hover_width = 0, hover_height = 0;
12445
12446 #define track_hover(track_hwnd, track_hover_time) \
12447 tme.cbSize = sizeof(tme); \
12448 tme.dwFlags = TME_HOVER; \
12449 tme.hwndTrack = track_hwnd; \
12450 tme.dwHoverTime = track_hover_time; \
12451 SetLastError(0xdeadbeef); \
12452 ret = pTrackMouseEvent(&tme); \
12453 ok(ret, "TrackMouseEvent(TME_HOVER) error %d\n", GetLastError())
12454
12455 #define track_query(expected_track_flags, expected_track_hwnd, expected_hover_time) \
12456 tme.cbSize = sizeof(tme); \
12457 tme.dwFlags = TME_QUERY; \
12458 tme.hwndTrack = (HWND)0xdeadbeef; \
12459 tme.dwHoverTime = 0xdeadbeef; \
12460 SetLastError(0xdeadbeef); \
12461 ret = pTrackMouseEvent(&tme); \
12462 ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());\
12463 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize); \
12464 ok(tme.dwFlags == (expected_track_flags), \
12465 "wrong tme.dwFlags %08x, expected %08x\n", tme.dwFlags, (expected_track_flags)); \
12466 ok(tme.hwndTrack == (expected_track_hwnd), \
12467 "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, (expected_track_hwnd)); \
12468 ok(tme.dwHoverTime == (expected_hover_time), \
12469 "wrong tme.dwHoverTime %u, expected %u\n", tme.dwHoverTime, (expected_hover_time))
12470
12471 #define track_hover_cancel(track_hwnd) \
12472 tme.cbSize = sizeof(tme); \
12473 tme.dwFlags = TME_HOVER | TME_CANCEL; \
12474 tme.hwndTrack = track_hwnd; \
12475 tme.dwHoverTime = 0xdeadbeef; \
12476 SetLastError(0xdeadbeef); \
12477 ret = pTrackMouseEvent(&tme); \
12478 ok(ret, "TrackMouseEvent(TME_HOVER | TME_CANCEL) error %d\n", GetLastError())
12479
12480 default_hover_time = 0xdeadbeef;
12481 SetLastError(0xdeadbeef);
12482 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERTIME, 0, &default_hover_time, 0);
12483 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
12484 "SystemParametersInfo(SPI_GETMOUSEHOVERTIME) error %u\n", GetLastError());
12485 if (!ret) default_hover_time = 400;
12486 trace("SPI_GETMOUSEHOVERTIME returned %u ms\n", default_hover_time);
12487
12488 SetLastError(0xdeadbeef);
12489 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERWIDTH, 0, &hover_width, 0);
12490 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
12491 "SystemParametersInfo(SPI_GETMOUSEHOVERWIDTH) error %u\n", GetLastError());
12492 if (!ret) hover_width = 4;
12493 SetLastError(0xdeadbeef);
12494 ret = SystemParametersInfoA(SPI_GETMOUSEHOVERHEIGHT, 0, &hover_height, 0);
12495 ok(ret || broken(GetLastError() == 0xdeadbeef), /* win9x */
12496 "SystemParametersInfo(SPI_GETMOUSEHOVERHEIGHT) error %u\n", GetLastError());
12497 if (!ret) hover_height = 4;
12498 trace("hover rect is %u x %d\n", hover_width, hover_height);
12499
12500 hwnd = CreateWindowExA(0, "TestWindowClass", NULL,
12501 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
12502 CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
12503 NULL, NULL, 0);
12504 assert(hwnd);
12505
12506 hchild = CreateWindowExA(0, "TestWindowClass", NULL,
12507 WS_CHILD | WS_BORDER | WS_VISIBLE,
12508 50, 50, 200, 200, hwnd,
12509 NULL, NULL, 0);
12510 assert(hchild);
12511
12512 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
12513 flush_events();
12514 flush_sequence();
12515
12516 tme.cbSize = 0;
12517 tme.dwFlags = TME_QUERY;
12518 tme.hwndTrack = (HWND)0xdeadbeef;
12519 tme.dwHoverTime = 0xdeadbeef;
12520 SetLastError(0xdeadbeef);
12521 ret = pTrackMouseEvent(&tme);
12522 ok(!ret, "TrackMouseEvent should fail\n");
12523 ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == 0xdeadbeef),
12524 "not expected error %u\n", GetLastError());
12525
12526 tme.cbSize = sizeof(tme);
12527 tme.dwFlags = TME_HOVER;
12528 tme.hwndTrack = (HWND)0xdeadbeef;
12529 tme.dwHoverTime = 0xdeadbeef;
12530 SetLastError(0xdeadbeef);
12531 ret = pTrackMouseEvent(&tme);
12532 ok(!ret, "TrackMouseEvent should fail\n");
12533 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
12534 "not expected error %u\n", GetLastError());
12535
12536 tme.cbSize = sizeof(tme);
12537 tme.dwFlags = TME_HOVER | TME_CANCEL;
12538 tme.hwndTrack = (HWND)0xdeadbeef;
12539 tme.dwHoverTime = 0xdeadbeef;
12540 SetLastError(0xdeadbeef);
12541 ret = pTrackMouseEvent(&tme);
12542 ok(!ret, "TrackMouseEvent should fail\n");
12543 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
12544 "not expected error %u\n", GetLastError());
12545
12546 GetWindowRect(hwnd, &rc_parent);
12547 GetWindowRect(hchild, &rc_child);
12548 SetCursorPos(rc_child.left - 10, rc_child.top - 10);
12549
12550 /* Process messages so that the system updates its internal current
12551 * window and hittest, otherwise TrackMouseEvent calls don't have any
12552 * effect.
12553 */
12554 flush_events();
12555 flush_sequence();
12556
12557 track_query(0, NULL, 0);
12558 track_hover(hchild, 0);
12559 track_query(0, NULL, 0);
12560
12561 flush_events();
12562 flush_sequence();
12563
12564 track_hover(hwnd, 0);
12565 tme.cbSize = sizeof(tme);
12566 tme.dwFlags = TME_QUERY;
12567 tme.hwndTrack = (HWND)0xdeadbeef;
12568 tme.dwHoverTime = 0xdeadbeef;
12569 SetLastError(0xdeadbeef);
12570 ret = pTrackMouseEvent(&tme);
12571 ok(ret, "TrackMouseEvent(TME_QUERY) error %d\n", GetLastError());
12572 ok(tme.cbSize == sizeof(tme), "wrong tme.cbSize %u\n", tme.cbSize);
12573 if (!tme.dwFlags)
12574 {
12575 skip( "Cursor not inside window, skipping TrackMouseEvent tests\n" );
12576 DestroyWindow( hwnd );
12577 return;
12578 }
12579 ok(tme.dwFlags == TME_HOVER, "wrong tme.dwFlags %08x, expected TME_HOVER\n", tme.dwFlags);
12580 ok(tme.hwndTrack == hwnd, "wrong tme.hwndTrack %p, expected %p\n", tme.hwndTrack, hwnd);
12581 ok(tme.dwHoverTime == default_hover_time, "wrong tme.dwHoverTime %u, expected %u\n",
12582 tme.dwHoverTime, default_hover_time);
12583
12584 pump_msg_loop_timeout(default_hover_time, FALSE);
12585 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12586
12587 track_query(0, NULL, 0);
12588
12589 track_hover(hwnd, HOVER_DEFAULT);
12590 track_query(TME_HOVER, hwnd, default_hover_time);
12591
12592 Sleep(default_hover_time / 2);
12593 mouse_event(MOUSEEVENTF_MOVE, -1, 0, 0, 0);
12594 mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0);
12595
12596 track_query(TME_HOVER, hwnd, default_hover_time);
12597
12598 pump_msg_loop_timeout(default_hover_time, FALSE);
12599 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12600
12601 track_query(0, NULL, 0);
12602
12603 track_hover(hwnd, HOVER_DEFAULT);
12604 track_query(TME_HOVER, hwnd, default_hover_time);
12605
12606 pump_msg_loop_timeout(default_hover_time, TRUE);
12607 ok_sequence(WmMouseHoverSeq, "WmMouseHoverSeq", FALSE);
12608
12609 track_query(0, NULL, 0);
12610
12611 track_hover(hwnd, HOVER_DEFAULT);
12612 track_query(TME_HOVER, hwnd, default_hover_time);
12613 track_hover_cancel(hwnd);
12614
12615 DestroyWindow(hwnd);
12616
12617 #undef track_hover
12618 #undef track_query
12619 #undef track_hover_cancel
12620 }
12621
12622
12623 static const struct message WmSetWindowRgn[] = {
12624 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12625 { WM_NCCALCSIZE, sent|wparam, 1 },
12626 { WM_NCPAINT, sent|optional }, /* wparam != 1 */
12627 { WM_GETTEXT, sent|defwinproc|optional },
12628 { WM_ERASEBKGND, sent|optional },
12629 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12630 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12631 { 0 }
12632 };
12633
12634 static const struct message WmSetWindowRgn_no_redraw[] = {
12635 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
12636 { WM_NCCALCSIZE, sent|wparam, 1 },
12637 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW },
12638 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12639 { 0 }
12640 };
12641
12642 static const struct message WmSetWindowRgn_clear[] = {
12643 { WM_WINDOWPOSCHANGING, sent/*|wparam*/, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE/*|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE only on some Windows versions */ },
12644 { WM_NCCALCSIZE, sent|wparam, 1 },
12645 { WM_NCPAINT, sent|optional },
12646 { WM_GETTEXT, sent|defwinproc|optional },
12647 { WM_ERASEBKGND, sent|optional }, /* FIXME: remove optional once Wine is fixed */
12648 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12649 { WM_NCCALCSIZE, sent|wparam|optional, 1 },
12650 { WM_NCPAINT, sent|optional },
12651 { WM_GETTEXT, sent|defwinproc|optional },
12652 { WM_ERASEBKGND, sent|optional },
12653 { WM_WINDOWPOSCHANGING, sent|optional },
12654 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
12655 { WM_NCPAINT, sent|optional },
12656 { WM_GETTEXT, sent|defwinproc|optional },
12657 { WM_ERASEBKGND, sent|optional },
12658 { WM_WINDOWPOSCHANGED, sent|optional|wparam, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE },
12659 { WM_NCCALCSIZE, sent|optional|wparam, 1 },
12660 { WM_NCPAINT, sent|optional },
12661 { WM_GETTEXT, sent|defwinproc|optional },
12662 { WM_ERASEBKGND, sent|optional },
12663 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12664 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
12665 { 0 }
12666 };
12667
12668 static void test_SetWindowRgn(void)
12669 {
12670 HRGN hrgn;
12671 HWND hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
12672 100, 100, 200, 200, 0, 0, 0, NULL);
12673 ok( hwnd != 0, "Failed to create overlapped window\n" );
12674
12675 ShowWindow( hwnd, SW_SHOW );
12676 UpdateWindow( hwnd );
12677 flush_events();
12678 flush_sequence();
12679
12680 trace("testing SetWindowRgn\n");
12681 hrgn = CreateRectRgn( 0, 0, 150, 150 );
12682 SetWindowRgn( hwnd, hrgn, TRUE );
12683 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn", FALSE );
12684
12685 hrgn = CreateRectRgn( 30, 30, 160, 160 );
12686 SetWindowRgn( hwnd, hrgn, FALSE );
12687 ok_sequence( WmSetWindowRgn_no_redraw, "WmSetWindowRgn_no_redraw", FALSE );
12688
12689 hrgn = CreateRectRgn( 0, 0, 180, 180 );
12690 SetWindowRgn( hwnd, hrgn, TRUE );
12691 ok_sequence( WmSetWindowRgn, "WmSetWindowRgn2", FALSE );
12692
12693 SetWindowRgn( hwnd, 0, TRUE );
12694 ok_sequence( WmSetWindowRgn_clear, "WmSetWindowRgn_clear", FALSE );
12695
12696 DestroyWindow( hwnd );
12697 }
12698
12699 /*************************** ShowWindow() test ******************************/
12700 static const struct message WmShowNormal[] = {
12701 { WM_SHOWWINDOW, sent|wparam, 1 },
12702 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12703 { HCBT_ACTIVATE, hook },
12704 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
12705 { HCBT_SETFOCUS, hook },
12706 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12707 { 0 }
12708 };
12709 static const struct message WmShow[] = {
12710 { WM_SHOWWINDOW, sent|wparam, 1 },
12711 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12712 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12713 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12714 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12715 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12716 { 0 }
12717 };
12718 static const struct message WmShowNoActivate_1[] = {
12719 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
12720 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12721 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12722 { WM_MOVE, sent|defwinproc|optional },
12723 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
12724 { 0 }
12725 };
12726 static const struct message WmShowNoActivate_2[] = {
12727 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE },
12728 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12729 { HCBT_ACTIVATE, hook|optional },
12730 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12731 { HCBT_SETFOCUS, hook|optional },
12732 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12733 { WM_MOVE, sent|defwinproc },
12734 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
12735 { HCBT_SETFOCUS, hook|optional },
12736 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
12737 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
12738 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12739 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
12740 { 0 }
12741 };
12742 static const struct message WmShowNA_1[] = {
12743 { WM_SHOWWINDOW, sent|wparam, 1 },
12744 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
12745 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12746 { 0 }
12747 };
12748 static const struct message WmShowNA_2[] = {
12749 { WM_SHOWWINDOW, sent|wparam, 1 },
12750 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
12751 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12752 { 0 }
12753 };
12754 static const struct message WmRestore_1[] = {
12755 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
12756 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12757 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12758 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12759 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12760 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12761 { WM_MOVE, sent|defwinproc },
12762 { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED },
12763 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
12764 { 0 }
12765 };
12766 static const struct message WmRestore_2[] = {
12767 { WM_SHOWWINDOW, sent|wparam, 1 },
12768 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12769 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12770 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12771 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12772 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12773 { 0 }
12774 };
12775 static const struct message WmRestore_3[] = {
12776 { HCBT_MINMAX, hook|lparam, 0, SW_RESTORE },
12777 { WM_GETMINMAXINFO, sent },
12778 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12779 { HCBT_ACTIVATE, hook|optional }, /* win2003 doesn't send it */
12780 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2003 doesn't send it */
12781 { HCBT_SETFOCUS, hook|optional }, /* win2003 doesn't send it */
12782 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12783 { WM_MOVE, sent|defwinproc },
12784 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
12785 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
12786 { 0 }
12787 };
12788 static const struct message WmRestore_4[] = {
12789 { HCBT_MINMAX, hook|lparam|optional, 0, SW_RESTORE },
12790 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12791 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12792 { WM_MOVE, sent|defwinproc|optional },
12793 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
12794 { 0 }
12795 };
12796 static const struct message WmRestore_5[] = {
12797 { HCBT_MINMAX, hook|lparam|optional, 0, SW_SHOWNORMAL },
12798 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12799 { HCBT_ACTIVATE, hook|optional },
12800 { HCBT_SETFOCUS, hook|optional },
12801 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12802 { WM_MOVE, sent|defwinproc|optional },
12803 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_RESTORED },
12804 { 0 }
12805 };
12806 static const struct message WmHide_1[] = {
12807 { WM_SHOWWINDOW, sent|wparam, 0 },
12808 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE, 0, SWP_NOACTIVATE },
12809 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE, 0, SWP_NOACTIVATE },
12810 { HCBT_ACTIVATE, hook|optional },
12811 { HCBT_SETFOCUS, hook|optional }, /* win2000 sends it */
12812 { 0 }
12813 };
12814 static const struct message WmHide_2[] = {
12815 { WM_SHOWWINDOW, sent|wparam, 0 },
12816 { WM_WINDOWPOSCHANGING, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
12817 { WM_WINDOWPOSCHANGED, sent /*|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE*/ }, /* win2000 doesn't add SWP_NOACTIVATE */
12818 { HCBT_ACTIVATE, hook|optional },
12819 { 0 }
12820 };
12821 static const struct message WmHide_3[] = {
12822 { WM_SHOWWINDOW, sent|wparam, 0 },
12823 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
12824 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12825 { HCBT_SETFOCUS, hook|optional },
12826 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
12827 { 0 }
12828 };
12829 static const struct message WmShowMinimized_1[] = {
12830 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
12831 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12832 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12833 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12834 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12835 { WM_MOVE, sent|defwinproc },
12836 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12837 { 0 }
12838 };
12839 static const struct message WmMinimize_1[] = {
12840 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
12841 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12842 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
12843 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12844 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12845 { WM_MOVE, sent|defwinproc },
12846 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12847 { 0 }
12848 };
12849 static const struct message WmMinimize_2[] = {
12850 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
12851 { HCBT_SETFOCUS, hook|optional },
12852 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12853 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12854 { WM_MOVE, sent|defwinproc },
12855 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12856 { 0 }
12857 };
12858 static const struct message WmMinimize_3[] = {
12859 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
12860 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12861 { HCBT_ACTIVATE, hook|optional },
12862 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12863 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED, 0, SWP_NOACTIVATE },
12864 { WM_MOVE, sent|defwinproc },
12865 { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 },
12866 { 0 }
12867 };
12868 static const struct message WmShowMinNoActivate[] = {
12869 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
12870 { WM_WINDOWPOSCHANGING, sent },
12871 { WM_WINDOWPOSCHANGED, sent },
12872 { WM_MOVE, sent|defwinproc|optional },
12873 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
12874 { 0 }
12875 };
12876 static const struct message WmMinMax_1[] = {
12877 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINIMIZED },
12878 { 0 }
12879 };
12880 static const struct message WmMinMax_2[] = {
12881 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
12882 { WM_GETMINMAXINFO, sent|optional },
12883 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED },
12884 { HCBT_ACTIVATE, hook|optional },
12885 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
12886 { HCBT_SETFOCUS, hook|optional },
12887 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
12888 { WM_MOVE, sent|defwinproc|optional },
12889 { WM_SIZE, sent|wparam|defwinproc|optional, SIZE_MAXIMIZED },
12890 { HCBT_SETFOCUS, hook|optional },
12891 { 0 }
12892 };
12893 static const struct message WmMinMax_3[] = {
12894 { HCBT_MINMAX, hook|lparam, 0, SW_MINIMIZE },
12895 { HCBT_SETFOCUS, hook|optional },
12896 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12897 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12898 { WM_MOVE, sent|defwinproc|optional },
12899 { WM_SIZE, sent|wparam|lparam|defwinproc|optional, SIZE_MINIMIZED, 0 },
12900 { 0 }
12901 };
12902 static const struct message WmMinMax_4[] = {
12903 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMINNOACTIVE },
12904 { 0 }
12905 };
12906 static const struct message WmShowMaximized_1[] = {
12907 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
12908 { WM_GETMINMAXINFO, sent },
12909 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12910 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12911 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12912 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12913 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12914 { WM_MOVE, sent|defwinproc },
12915 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
12916 { HCBT_SETFOCUS, hook|optional }, /* win2003 sends it */
12917 { 0 }
12918 };
12919 static const struct message WmShowMaximized_2[] = {
12920 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
12921 { WM_GETMINMAXINFO, sent },
12922 { WM_WINDOWPOSCHANGING, sent|optional },
12923 { HCBT_ACTIVATE, hook|optional },
12924 { WM_WINDOWPOSCHANGED, sent|optional },
12925 { WM_MOVE, sent|optional }, /* Win9x doesn't send it */
12926 { WM_SIZE, sent|wparam|optional, SIZE_MAXIMIZED }, /* Win9x doesn't send it */
12927 { WM_WINDOWPOSCHANGING, sent|optional },
12928 { HCBT_SETFOCUS, hook|optional },
12929 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED },
12930 { WM_MOVE, sent|defwinproc },
12931 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
12932 { HCBT_SETFOCUS, hook|optional },
12933 { 0 }
12934 };
12935 static const struct message WmShowMaximized_3[] = {
12936 { HCBT_MINMAX, hook|lparam, 0, SW_SHOWMAXIMIZED },
12937 { WM_GETMINMAXINFO, sent|optional },
12938 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12939 { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */
12940 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */
12941 { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */
12942 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE },
12943 { WM_MOVE, sent|defwinproc|optional },
12944 { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED },
12945 { 0 }
12946 };
12947
12948 static void test_ShowWindow(void)
12949 {
12950 /* ShowWindow commands in random order */
12951 static const struct
12952 {
12953 INT cmd; /* ShowWindow command */
12954 LPARAM ret; /* ShowWindow return value */
12955 DWORD style; /* window style after the command */
12956 const struct message *msg; /* message sequence the command produces */
12957 INT wp_cmd, wp_flags; /* window placement after the command */
12958 POINT wp_min, wp_max; /* window placement after the command */
12959 BOOL todo_msg; /* message sequence doesn't match what Wine does */
12960 } sw[] =
12961 {
12962 /* 1 */ { SW_SHOWNORMAL, FALSE, WS_VISIBLE, WmShowNormal,
12963 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
12964 /* 2 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmEmptySeq,
12965 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
12966 /* 3 */ { SW_HIDE, TRUE, 0, WmHide_1,
12967 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
12968 /* 4 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
12969 SW_SHOWNORMAL, 0, {-1,-1}, {-1,-1}, FALSE },
12970 /* 5 */ { SW_SHOWMINIMIZED, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinimized_1,
12971 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12972 /* 6 */ { SW_SHOWMINIMIZED, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_1,
12973 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12974 /* 7 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_1,
12975 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12976 /* 8 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
12977 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
12978 /* 9 */ { SW_SHOWMAXIMIZED, FALSE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_1,
12979 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12980 /* 10 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
12981 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12982 /* 11 */ { SW_HIDE, TRUE, WS_MAXIMIZE, WmHide_1,
12983 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12984 /* 12 */ { SW_HIDE, FALSE, WS_MAXIMIZE, WmEmptySeq,
12985 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
12986 /* 13 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_1,
12987 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12988 /* 14 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
12989 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12990 /* 15 */ { SW_HIDE, TRUE, 0, WmHide_2,
12991 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12992 /* 16 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
12993 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12994 /* 17 */ { SW_SHOW, FALSE, WS_VISIBLE, WmShow,
12995 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12996 /* 18 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
12997 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
12998 /* 19 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
12999 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13000 /* 20 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13001 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13002 /* 21 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13003 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13004 /* 22 */ { SW_SHOWMINNOACTIVE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowMinNoActivate,
13005 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, TRUE },
13006 /* 23 */ { SW_SHOWMINNOACTIVE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_4,
13007 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13008 /* 24 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13009 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13010 /* 25 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
13011 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13012 /* 26 */ { SW_SHOWNA, FALSE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_1,
13013 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13014 /* 27 */ { SW_SHOWNA, TRUE, WS_VISIBLE|WS_MINIMIZE, WmShowNA_2,
13015 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13016 /* 28 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13017 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13018 /* 29 */ { SW_HIDE, FALSE, WS_MINIMIZE, WmEmptySeq,
13019 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13020 /* 30 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_1,
13021 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13022 /* 31 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
13023 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13024 /* 32 */ { SW_HIDE, TRUE, 0, WmHide_3,
13025 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13026 /* 33 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13027 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13028 /* 34 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq, /* what does this mean?! */
13029 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13030 /* 35 */ { SW_NORMALNA, FALSE, 0, WmEmptySeq,
13031 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13032 /* 36 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13033 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13034 /* 37 */ { SW_RESTORE, FALSE, WS_VISIBLE, WmRestore_2,
13035 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13036 /* 38 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmEmptySeq,
13037 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13038 /* 39 */ { SW_SHOWNOACTIVATE, TRUE, WS_VISIBLE, WmEmptySeq,
13039 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13040 /* 40 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_2,
13041 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13042 /* 41 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13043 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13044 /* 42 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_2,
13045 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13046 /* 43 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmMinMax_2,
13047 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13048 /* 44 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_1,
13049 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13050 /* 45 */ { SW_MINIMIZE, TRUE, WS_VISIBLE|WS_MINIMIZE, WmMinMax_3,
13051 SW_SHOWMINIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13052 /* 46 */ { SW_RESTORE, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmRestore_3,
13053 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13054 /* 47 */ { SW_RESTORE, TRUE, WS_VISIBLE, WmRestore_4,
13055 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13056 /* 48 */ { SW_SHOWMAXIMIZED, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmShowMaximized_3,
13057 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13058 /* 49 */ { SW_SHOW, TRUE, WS_VISIBLE|WS_MAXIMIZE, WmEmptySeq,
13059 SW_SHOWMAXIMIZED, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13060 /* 50 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
13061 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13062 /* 51 */ { SW_SHOWNORMAL, TRUE, WS_VISIBLE, WmRestore_5,
13063 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13064 /* 52 */ { SW_HIDE, TRUE, 0, WmHide_1,
13065 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13066 /* 53 */ { SW_HIDE, FALSE, 0, WmEmptySeq,
13067 SW_SHOWNORMAL, WPF_RESTORETOMAXIMIZED, {-32000,-32000}, {-1,-1}, FALSE },
13068 /* 54 */ { SW_MINIMIZE, FALSE, WS_VISIBLE|WS_MINIMIZE, WmMinimize_3,
13069 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13070 /* 55 */ { SW_HIDE, TRUE, WS_MINIMIZE, WmHide_2,
13071 SW_SHOWMINIMIZED, 0, {-32000,-32000}, {-1,-1}, FALSE },
13072 /* 56 */ { SW_SHOWNOACTIVATE, FALSE, WS_VISIBLE, WmShowNoActivate_2,
13073 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE },
13074 /* 57 */ { SW_SHOW, TRUE, WS_VISIBLE, WmEmptySeq,
13075 SW_SHOWNORMAL, 0, {-32000,-32000}, {-1,-1}, FALSE }
13076 };
13077 HWND hwnd;
13078 DWORD style;
13079 LPARAM ret;
13080 INT i;
13081 WINDOWPLACEMENT wp;
13082 RECT win_rc, work_rc = {0, 0, 0, 0};
13083
13084 #define WS_BASE (WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_POPUP|WS_CLIPSIBLINGS)
13085 hwnd = CreateWindowExA(0, "ShowWindowClass", NULL, WS_BASE,
13086 120, 120, 90, 90,
13087 0, 0, 0, NULL);
13088 assert(hwnd);
13089
13090 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
13091 ok(style == 0, "expected style 0, got %08x\n", style);
13092
13093 flush_events();
13094 flush_sequence();
13095
13096 if (pGetMonitorInfoA && pMonitorFromPoint)
13097 {
13098 HMONITOR hmon;
13099 MONITORINFO mi;
13100 POINT pt = {0, 0};
13101
13102 SetLastError(0xdeadbeef);
13103 hmon = pMonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
13104 ok(hmon != 0, "MonitorFromPoint error %u\n", GetLastError());
13105
13106 mi.cbSize = sizeof(mi);
13107 SetLastError(0xdeadbeef);
13108 ret = pGetMonitorInfoA(hmon, &mi);
13109 ok(ret, "GetMonitorInfo error %u\n", GetLastError());
13110 trace("monitor %s, work %s\n", wine_dbgstr_rect(&mi.rcMonitor),
13111 wine_dbgstr_rect(&mi.rcWork));
13112 work_rc = mi.rcWork;
13113 }
13114
13115 GetWindowRect(hwnd, &win_rc);
13116 OffsetRect(&win_rc, -work_rc.left, -work_rc.top);
13117
13118 wp.length = sizeof(wp);
13119 SetLastError(0xdeadbeaf);
13120 ret = GetWindowPlacement(hwnd, &wp);
13121 ok(ret, "GetWindowPlacement error %u\n", GetLastError());
13122 ok(wp.flags == 0, "expected 0, got %#x\n", wp.flags);
13123 ok(wp.showCmd == SW_SHOWNORMAL, "expected SW_SHOWNORMAL, got %d\n", wp.showCmd);
13124 ok(wp.ptMinPosition.x == -1 && wp.ptMinPosition.y == -1,
13125 "expected -1,-1 got %d,%d\n", wp.ptMinPosition.x, wp.ptMinPosition.y);
13126 ok(wp.ptMaxPosition.x == -1 && wp.ptMaxPosition.y == -1,
13127 "expected -1,-1 got %d,%d\n", wp.ptMaxPosition.x, wp.ptMaxPosition.y);
13128 todo_wine_if (work_rc.left || work_rc.top) /* FIXME: remove once Wine is fixed */
13129 ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n", wine_dbgstr_rect(&win_rc),
13130 wine_dbgstr_rect(&wp.rcNormalPosition));
13131
13132 for (i = 0; i < sizeof(sw)/sizeof(sw[0]); i++)
13133 {
13134 static const char * const sw_cmd_name[13] =
13135 {
13136 "SW_HIDE", "SW_SHOWNORMAL", "SW_SHOWMINIMIZED", "SW_SHOWMAXIMIZED",
13137 "SW_SHOWNOACTIVATE", "SW_SHOW", "SW_MINIMIZE", "SW_SHOWMINNOACTIVE",
13138 "SW_SHOWNA", "SW_RESTORE", "SW_SHOWDEFAULT", "SW_FORCEMINIMIZE",
13139 "SW_NORMALNA" /* 0xCC */
13140 };
13141 char comment[64];
13142 INT idx; /* index into the above array of names */
13143
13144 idx = (sw[i].cmd == SW_NORMALNA) ? 12 : sw[i].cmd;
13145
13146 style = GetWindowLongA(hwnd, GWL_STYLE);
13147 trace("%d: sending %s, current window style %08x\n", i+1, sw_cmd_name[idx], style);
13148 ret = ShowWindow(hwnd, sw[i].cmd);
13149 ok(!ret == !sw[i].ret, "%d: cmd %s: expected ret %lu, got %lu\n", i+1, sw_cmd_name[idx], sw[i].ret, ret);
13150 style = GetWindowLongA(hwnd, GWL_STYLE) & ~WS_BASE;
13151 ok(style == sw[i].style, "%d: expected style %08x, got %08x\n", i+1, sw[i].style, style);
13152
13153 sprintf(comment, "%d: ShowWindow(%s)", i+1, sw_cmd_name[idx]);
13154 ok_sequence(sw[i].msg, comment, sw[i].todo_msg);
13155
13156 wp.length = sizeof(wp);
13157 SetLastError(0xdeadbeaf);
13158 ret = GetWindowPlacement(hwnd, &wp);
13159 ok(ret, "GetWindowPlacement error %u\n", GetLastError());
13160 ok(wp.flags == sw[i].wp_flags, "expected %#x, got %#x\n", sw[i].wp_flags, wp.flags);
13161 ok(wp.showCmd == sw[i].wp_cmd, "expected %d, got %d\n", sw[i].wp_cmd, wp.showCmd);
13162
13163 /* NT moves the minimized window to -32000,-32000, win9x to 3000,3000 */
13164 if ((wp.ptMinPosition.x + work_rc.left == -32000 && wp.ptMinPosition.y + work_rc.top == -32000) ||
13165 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000))
13166 {
13167 ok((wp.ptMinPosition.x + work_rc.left == sw[i].wp_min.x && wp.ptMinPosition.y + work_rc.top == sw[i].wp_min.y) ||
13168 (wp.ptMinPosition.x + work_rc.left == 3000 && wp.ptMinPosition.y + work_rc.top == 3000),
13169 "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
13170 }
13171 else
13172 {
13173 ok(wp.ptMinPosition.x == sw[i].wp_min.x && wp.ptMinPosition.y == sw[i].wp_min.y,
13174 "expected %d,%d got %d,%d\n", sw[i].wp_min.x, sw[i].wp_min.y, wp.ptMinPosition.x, wp.ptMinPosition.y);
13175 }
13176
13177 todo_wine_if(wp.ptMaxPosition.x != sw[i].wp_max.x || wp.ptMaxPosition.y != sw[i].wp_max.y)
13178 ok(wp.ptMaxPosition.x == sw[i].wp_max.x && wp.ptMaxPosition.y == sw[i].wp_max.y,
13179 "expected %d,%d got %d,%d\n", sw[i].wp_max.x, sw[i].wp_max.y, wp.ptMaxPosition.x, wp.ptMaxPosition.y);
13180
13181 if (0) /* FIXME: Wine behaves completely different here */
13182 ok(EqualRect(&win_rc, &wp.rcNormalPosition), "expected %s got %s\n",
13183 wine_dbgstr_rect(&win_rc), wine_dbgstr_rect(&wp.rcNormalPosition));
13184 }
13185 DestroyWindow(hwnd);
13186 flush_events();
13187 }
13188
13189 static INT_PTR WINAPI test_dlg_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13190 {
13191 struct recvd_message msg;
13192
13193 if (ignore_message( message )) return 0;
13194
13195 msg.hwnd = hwnd;
13196 msg.message = message;
13197 msg.flags = sent|wparam|lparam;
13198 msg.wParam = wParam;
13199 msg.lParam = lParam;
13200 msg.descr = "dialog";
13201 add_message(&msg);
13202
13203 /* calling DefDlgProc leads to a recursion under XP */
13204
13205 switch (message)
13206 {
13207 case WM_INITDIALOG:
13208 return lParam;
13209
13210 case WM_GETDLGCODE:
13211 return 0;
13212 }
13213 return 1;
13214 }
13215
13216 static WNDPROC orig_edit_proc;
13217 static LRESULT WINAPI dlg_creation_edit_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
13218 {
13219 struct recvd_message msg;
13220
13221 if (ignore_message( message )) return 0;
13222
13223 msg.hwnd = hwnd;
13224 msg.message = message;
13225 msg.flags = sent|wparam|lparam;
13226 msg.wParam = wp;
13227 msg.lParam = lp;
13228 msg.descr = "edit";
13229 add_message(&msg);
13230
13231 return CallWindowProcW(orig_edit_proc, hwnd, message, wp, lp);
13232 }
13233
13234 static INT_PTR WINAPI test_dlg_proc2(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13235 {
13236 struct recvd_message msg;
13237
13238 if (ignore_message( message )) return 0;
13239
13240 msg.hwnd = hwnd;
13241 msg.message = message;
13242 msg.flags = sent|wparam|lparam|parent;
13243 msg.wParam = wParam;
13244 msg.lParam = lParam;
13245 msg.descr = "dialog";
13246 add_message(&msg);
13247
13248 if (message == WM_INITDIALOG)
13249 {
13250 orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
13251 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
13252 }
13253
13254 return 1;
13255 }
13256
13257 static INT_PTR WINAPI test_dlg_proc3(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13258 {
13259 ok( 0, "should not be called since DefDlgProc is not used\n" );
13260 return 0;
13261 }
13262
13263 static LRESULT WINAPI test_dlg_proc4(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
13264 {
13265 struct recvd_message msg;
13266
13267 if (!ignore_message( message ))
13268 {
13269 msg.hwnd = hwnd;
13270 msg.message = message;
13271 msg.flags = sent|wparam|lparam|parent;
13272 msg.wParam = wParam;
13273 msg.lParam = lParam;
13274 msg.descr = "dialog";
13275 add_message(&msg);
13276 }
13277 if (message == WM_INITDIALOG)
13278 {
13279 orig_edit_proc = (WNDPROC)SetWindowLongPtrW(GetDlgItem(hwnd, 200),
13280 GWLP_WNDPROC, (LONG_PTR)dlg_creation_edit_proc);
13281 return 1;
13282 }
13283 return DefWindowProcW( hwnd, message, wParam, lParam );
13284 }
13285
13286 static const struct message WmDefDlgSetFocus_1[] = {
13287 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13288 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
13289 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
13290 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
13291 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
13292 { HCBT_SETFOCUS, hook },
13293 { WM_IME_SETCONTEXT, sent|wparam|optional, 1 },
13294 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13295 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
13296 { WM_SETFOCUS, sent|wparam, 0 },
13297 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 10 },
13298 { WM_CTLCOLOREDIT, sent },
13299 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 11 },
13300 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13301 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13302 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13303 { WM_COMMAND, sent|wparam, MAKEWPARAM(1, EN_SETFOCUS) },
13304 { 0 }
13305 };
13306 static const struct message WmDefDlgSetFocus_2[] = {
13307 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13308 { WM_GETTEXTLENGTH, sent|wparam|lparam|optional, 0, 0 }, /* XP */
13309 { WM_GETTEXT, sent|wparam|optional, 6 }, /* XP */
13310 { WM_GETTEXT, sent|wparam|optional, 12 }, /* XP */
13311 { EM_SETSEL, sent|wparam, 0 }, /* XP sets lparam to text length, Win9x to -2 */
13312 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13313 { WM_CTLCOLOREDIT, sent|optional }, /* XP */
13314 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, OBJID_CARET, 0 },
13315 { 0 }
13316 };
13317 /* Creation of a dialog */
13318 static const struct message WmCreateDialogParamSeq_0[] = {
13319 { HCBT_CREATEWND, hook },
13320 { WM_NCCREATE, sent },
13321 { WM_NCCALCSIZE, sent|wparam, 0 },
13322 { WM_CREATE, sent },
13323 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13324 { WM_SIZE, sent|wparam, SIZE_RESTORED },
13325 { WM_MOVE, sent },
13326 { WM_SETFONT, sent },
13327 { WM_INITDIALOG, sent },
13328 { WM_CHANGEUISTATE, sent|optional },
13329 { 0 }
13330 };
13331 /* Creation of a dialog */
13332 static const struct message WmCreateDialogParamSeq_1[] = {
13333 { HCBT_CREATEWND, hook },
13334 { WM_NCCREATE, sent },
13335 { WM_NCCALCSIZE, sent|wparam, 0 },
13336 { WM_CREATE, sent },
13337 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13338 { WM_SIZE, sent|wparam, SIZE_RESTORED },
13339 { WM_MOVE, sent },
13340 { WM_SETFONT, sent },
13341 { WM_INITDIALOG, sent },
13342 { WM_GETDLGCODE, sent|wparam|lparam|optional, 0, 0 }, /* FIXME: Wine doesn't send it */
13343 { HCBT_SETFOCUS, hook },
13344 { HCBT_ACTIVATE, hook },
13345 { WM_QUERYNEWPALETTE, sent|optional },
13346 { WM_PALETTEISCHANGING, sent|optional },
13347 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13348 { WM_ACTIVATEAPP, sent|wparam, 1 },
13349 { WM_NCACTIVATE, sent },
13350 { WM_ACTIVATE, sent|wparam, 1 },
13351 { WM_SETFOCUS, sent },
13352 { WM_CHANGEUISTATE, sent|optional },
13353 { 0 }
13354 };
13355 /* Creation of a dialog */
13356 static const struct message WmCreateDialogParamSeq_2[] = {
13357 { HCBT_CREATEWND, hook },
13358 { WM_NCCREATE, sent },
13359 { WM_NCCALCSIZE, sent|wparam, 0 },
13360 { WM_CREATE, sent },
13361 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13362 { WM_SIZE, sent|wparam, SIZE_RESTORED },
13363 { WM_MOVE, sent },
13364 { WM_CHANGEUISTATE, sent|optional },
13365 { 0 }
13366 };
13367
13368 static const struct message WmCreateDialogParamSeq_3[] = {
13369 { HCBT_CREATEWND, hook },
13370 { WM_SETFONT, sent|parent },
13371 { WM_INITDIALOG, sent|parent },
13372 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13373 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
13374 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13375 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13376 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13377 { HCBT_ACTIVATE, hook },
13378 { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
13379 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13380 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13381 { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
13382 { WM_NCACTIVATE, sent|parent },
13383 { WM_ACTIVATE, sent|parent|wparam, 1 },
13384 { WM_SETFOCUS, sent },
13385 { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
13386 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13387 { WM_USER, sent|parent },
13388 { WM_CHANGEUISTATE, sent|parent|optional },
13389 { 0 }
13390 };
13391
13392 static const struct message WmCreateDialogParamSeq_4[] = {
13393 { HCBT_CREATEWND, hook },
13394 { WM_NCCREATE, sent|parent },
13395 { WM_NCCALCSIZE, sent|parent|wparam, 0 },
13396 { WM_CREATE, sent|parent },
13397 { EVENT_OBJECT_CREATE, winevent_hook|wparam|lparam, 0, 0 },
13398 { WM_SIZE, sent|parent|wparam, SIZE_RESTORED },
13399 { WM_MOVE, sent|parent },
13400 { WM_SETFONT, sent|parent },
13401 { WM_INITDIALOG, sent|parent },
13402 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13403 { EM_SETSEL, sent|wparam|lparam, 0, INT_MAX },
13404 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13405 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13406 { EM_SETSEL, sent|wparam|lparam|optional, 0, INT_MAX },
13407 { HCBT_ACTIVATE, hook },
13408 { WM_QUERYNEWPALETTE, sent|parent|optional }, /* TODO: this message should not be sent */
13409 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13410 { WM_WINDOWPOSCHANGING, sent|parent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13411 { WM_ACTIVATEAPP, sent|parent|wparam, 1 },
13412 { WM_NCACTIVATE, sent|parent },
13413 { WM_ACTIVATE, sent|parent|wparam, 1 },
13414 { HCBT_SETFOCUS, hook },
13415 { WM_SETFOCUS, sent|parent },
13416 { WM_KILLFOCUS, sent|parent },
13417 { WM_SETFOCUS, sent },
13418 { WM_COMMAND, sent|parent|wparam, MAKELONG(200, EN_SETFOCUS) },
13419 { WM_GETDLGCODE, sent|wparam|lparam, 0, 0 },
13420 { WM_USER, sent|parent },
13421 { WM_CHANGEUISTATE, sent|parent|optional },
13422 { WM_UPDATEUISTATE, sent|parent|optional },
13423 { WM_UPDATEUISTATE, sent|optional },
13424 { 0 }
13425 };
13426
13427 static void test_dialog_messages(void)
13428 {
13429 WNDCLASSA cls;
13430 HWND hdlg, hedit1, hedit2, hfocus, parent, child, child2;
13431 LRESULT ret;
13432
13433 #define set_selection(hctl, start, end) \
13434 ret = SendMessageA(hctl, EM_SETSEL, start, end); \
13435 ok(ret == 1, "EM_SETSEL returned %ld\n", ret);
13436
13437 #define check_selection(hctl, start, end) \
13438 ret = SendMessageA(hctl, EM_GETSEL, 0, 0); \
13439 ok(ret == MAKELRESULT(start, end), "wrong selection (%d - %d)\n", LOWORD(ret), HIWORD(ret));
13440
13441 subclass_edit();
13442
13443 hdlg = CreateWindowExA(WS_EX_DLGMODALFRAME, "TestDialogClass", NULL,
13444 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
13445 0, 0, 100, 100, 0, 0, 0, NULL);
13446 ok(hdlg != 0, "Failed to create custom dialog window\n");
13447
13448 hedit1 = CreateWindowExA(0, "my_edit_class", NULL,
13449 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
13450 0, 0, 80, 20, hdlg, (HMENU)1, 0, NULL);
13451 ok(hedit1 != 0, "Failed to create edit control\n");
13452 hedit2 = CreateWindowExA(0, "my_edit_class", NULL,
13453 WS_CHILD|WS_BORDER|WS_VISIBLE|WS_TABSTOP,
13454 0, 40, 80, 20, hdlg, (HMENU)2, 0, NULL);
13455 ok(hedit2 != 0, "Failed to create edit control\n");
13456
13457 SendMessageA(hedit1, WM_SETTEXT, 0, (LPARAM)"hello");
13458 SendMessageA(hedit2, WM_SETTEXT, 0, (LPARAM)"bye");
13459
13460 hfocus = GetFocus();
13461 ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
13462
13463 SetFocus(hedit2);
13464 hfocus = GetFocus();
13465 ok(hfocus == hedit2, "wrong focus %p\n", hfocus);
13466
13467 check_selection(hedit1, 0, 0);
13468 check_selection(hedit2, 0, 0);
13469
13470 set_selection(hedit2, 0, -1);
13471 check_selection(hedit2, 0, 3);
13472
13473 SetFocus(0);
13474 hfocus = GetFocus();
13475 ok(hfocus == 0, "wrong focus %p\n", hfocus);
13476
13477 flush_sequence();
13478 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
13479 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
13480 ok_sequence(WmDefDlgSetFocus_1, "DefDlgProc(WM_SETFOCUS) 1", FALSE);
13481
13482 hfocus = GetFocus();
13483 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
13484
13485 check_selection(hedit1, 0, 5);
13486 check_selection(hedit2, 0, 3);
13487
13488 flush_sequence();
13489 ret = DefDlgProcA(hdlg, WM_SETFOCUS, 0, 0);
13490 ok(ret == 0, "WM_SETFOCUS returned %ld\n", ret);
13491 ok_sequence(WmDefDlgSetFocus_2, "DefDlgProc(WM_SETFOCUS) 2", FALSE);
13492
13493 hfocus = GetFocus();
13494 ok(hfocus == hedit1, "wrong focus %p\n", hfocus);
13495
13496 check_selection(hedit1, 0, 5);
13497 check_selection(hedit2, 0, 3);
13498
13499 EndDialog(hdlg, 0);
13500 DestroyWindow(hedit1);
13501 DestroyWindow(hedit2);
13502 DestroyWindow(hdlg);
13503 flush_sequence();
13504
13505 #undef set_selection
13506 #undef check_selection
13507
13508 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
13509 cls.lpszClassName = "MyDialogClass";
13510 cls.hInstance = GetModuleHandleA(NULL);
13511 /* need a cast since a dlgproc is used as a wndproc */
13512 cls.lpfnWndProc = test_dlg_proc;
13513 if (!RegisterClassA(&cls)) assert(0);
13514
13515 SetFocus(0);
13516 flush_sequence();
13517 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 0);
13518 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13519 ok_sequence(WmCreateDialogParamSeq_0, "CreateDialogParam_0", FALSE);
13520 hfocus = GetFocus();
13521 ok(hfocus == 0, "wrong focus %p\n", hfocus);
13522 EndDialog(hdlg, 0);
13523 DestroyWindow(hdlg);
13524 flush_sequence();
13525
13526 SetFocus(0);
13527 flush_sequence();
13528 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, test_dlg_proc, 1);
13529 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13530 ok_sequence(WmCreateDialogParamSeq_1, "CreateDialogParam_1", FALSE);
13531 hfocus = GetFocus();
13532 ok(hfocus == hdlg, "wrong focus %p\n", hfocus);
13533 EndDialog(hdlg, 0);
13534 DestroyWindow(hdlg);
13535 flush_sequence();
13536
13537 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", 0, NULL, 0);
13538 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13539 ok_sequence(WmCreateDialogParamSeq_2, "CreateDialogParam_2", FALSE);
13540 EndDialog(hdlg, 0);
13541 DestroyWindow(hdlg);
13542 flush_sequence();
13543
13544 hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_3", 0, test_dlg_proc2, 0);
13545 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13546 ok_sequence(WmCreateDialogParamSeq_3, "CreateDialogParam_3", TRUE);
13547 EndDialog(hdlg, 0);
13548 DestroyWindow(hdlg);
13549 flush_sequence();
13550
13551 UnregisterClassA( cls.lpszClassName, cls.hInstance );
13552 cls.lpfnWndProc = test_dlg_proc4;
13553 ok( RegisterClassA(&cls), "failed to register class again\n" );
13554 hdlg = CreateDialogParamA(0, "FOCUS_TEST_DIALOG_4", 0, test_dlg_proc3, 0);
13555 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13556 ok_sequence(WmCreateDialogParamSeq_4, "CreateDialogParam_4", TRUE);
13557 EndDialog(hdlg, 0);
13558 DestroyWindow(hdlg);
13559 flush_sequence();
13560
13561 UnregisterClassA(cls.lpszClassName, cls.hInstance);
13562
13563 parent = CreateWindowExA(0, "TestParentClass", "Test parent",
13564 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13565 100, 100, 200, 200, 0, 0, 0, NULL);
13566 ok (parent != 0, "Failed to create parent window\n");
13567
13568 /* This child has no parent set. We will later call SetParent on it,
13569 * so that it will have a parent set, but no WS_CHILD style. */
13570 child = CreateWindowExA(0, "TestWindowClass", "Test child",
13571 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13572 100, 100, 200, 200, 0, 0, 0, NULL);
13573 ok (child != 0, "Failed to create child window\n");
13574
13575 /* This is a regular child window. When used as an owner, the other
13576 * child window will be used. */
13577 child2 = CreateWindowExA(0, "SimpleWindowClass", "Test child2",
13578 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CHILD,
13579 100, 100, 200, 200, child, 0, 0, NULL);
13580 ok (child2 != 0, "Failed to create child window\n");
13581
13582 SetParent(child, parent);
13583 SetFocus(child);
13584
13585 flush_sequence();
13586 DialogBoxA( 0, "TEST_DIALOG", child2, TestModalDlgProc2 );
13587 ok_sequence(WmModalDialogSeq_2, "ModalDialog2", TRUE);
13588
13589 DestroyWindow(child2);
13590 DestroyWindow(child);
13591 DestroyWindow(parent);
13592 flush_sequence();
13593 }
13594
13595 static void test_enddialog_seq(HWND dialog, HWND owner)
13596 {
13597 const struct message seq[] = {
13598 { WM_ENABLE, sent },
13599 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13600 { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
13601 { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13602 { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13603 /* FIXME: Following two are optional because Wine sends WM_QUERYNEWPALETTE instead of WM_WINDOWPOSCHANGING */
13604 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13605 { WM_QUERYNEWPALETTE, sent|optional },
13606 { WM_NCACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
13607 { WM_GETTEXT, sent|optional|defwinproc },
13608 { WM_ACTIVATE, sent|wparam|lparam, WA_ACTIVE, (LPARAM)dialog },
13609 { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
13610 { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
13611 { WM_SETFOCUS, sent|defwinproc|wparam, (WPARAM)dialog },
13612 { 0 }
13613 };
13614
13615 flush_sequence();
13616 EndDialog(dialog, 0);
13617 ok_sequence(seq, "EndDialog", FALSE);
13618 }
13619
13620 static void test_enddialog_seq2(HWND dialog, HWND owner)
13621 {
13622 const struct message seq[] = {
13623 { WM_ENABLE, parent|sent },
13624 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13625 { HCBT_ACTIVATE, hook|wparam, (WPARAM)owner },
13626 { WM_NCACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13627 { WM_ACTIVATE, sent|wparam|lparam, WA_INACTIVE, (LPARAM)owner },
13628 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13629 { WM_WINDOWPOSCHANGING, sent|optional|wparam, SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
13630 { HCBT_SETFOCUS, hook|wparam, (WPARAM)owner },
13631 { WM_KILLFOCUS, sent|wparam, (WPARAM)owner },
13632 { WM_SETFOCUS, sent|parent|defwinproc|wparam, (WPARAM)dialog },
13633 { 0 }
13634 };
13635
13636 flush_sequence();
13637 EndDialog(dialog, 0);
13638 ok_sequence(seq, "EndDialog2", FALSE);
13639 }
13640
13641 static void test_EndDialog(void)
13642 {
13643 HWND hparent, hother, hactive, hdlg, hchild;
13644 WNDCLASSA cls;
13645
13646 hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
13647 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
13648 100, 100, 200, 200, 0, 0, 0, NULL);
13649 ok (hparent != 0, "Failed to create parent window\n");
13650
13651 hother = CreateWindowExA(0, "TestParentClass", "Test parent 2",
13652 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13653 200, 100, 200, 200, 0, 0, 0, NULL);
13654 ok (hother != 0, "Failed to create parent window\n");
13655
13656 ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
13657 cls.lpszClassName = "MyDialogClass";
13658 cls.hInstance = GetModuleHandleA(NULL);
13659 cls.lpfnWndProc = test_dlg_proc;
13660 if (!RegisterClassA(&cls)) assert(0);
13661
13662 flush_sequence();
13663 SetForegroundWindow(hother);
13664 hactive = GetForegroundWindow();
13665 ok(hother == hactive, "Wrong window has focus (%p != %p)\n", hother, hactive);
13666
13667 /* create a dialog where the parent is disabled, this parent should be
13668 * enabled and receive focus when dialog exits */
13669 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hparent, test_dlg_proc, 0);
13670 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13671 SetForegroundWindow(hdlg);
13672 hactive = GetForegroundWindow();
13673 ok(hdlg == hactive, "Wrong window has focus (%p != %p)\n", hdlg, hactive);
13674 EndDialog(hdlg, 0);
13675 ok(IsWindowEnabled(hparent), "parent is not enabled\n");
13676 hactive = GetForegroundWindow();
13677 ok(hparent == hactive, "Wrong window has focus (parent != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
13678 DestroyWindow(hdlg);
13679 flush_sequence();
13680
13681 /* create a dialog where the parent is disabled and set active window to other window before calling EndDialog */
13682 EnableWindow(hparent, FALSE);
13683 hdlg = CreateWindowExA(0, "TestDialogClass", NULL,
13684 WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_DLGFRAME,
13685 0, 0, 100, 100, hparent, 0, 0, NULL);
13686 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13687 flush_sequence();
13688 SetForegroundWindow(hother);
13689 flush_sequence();
13690 hactive = GetForegroundWindow();
13691 ok(hactive == hother, "Wrong foreground (%p != %p)\n", hactive, hother);
13692 hactive = GetActiveWindow();
13693 ok(hactive == hother, "Wrong active window (%p != %p)\n", hactive, hother);
13694 EndDialog(hdlg, 0);
13695 ok(IsWindowEnabled(hparent), "parent is not enabled\n");
13696 hactive = GetForegroundWindow();
13697 ok(hother == hactive, "Wrong window has focus (other != active) (active: %p, parent: %p, dlg: %p, other: %p)\n", hactive, hparent, hdlg, hother);
13698 DestroyWindow(hdlg);
13699 flush_sequence();
13700
13701 DestroyWindow( hparent );
13702
13703 hparent = CreateWindowExA(0, "TestParentClass", "Test parent",
13704 WS_POPUP | WS_VISIBLE | WS_DISABLED,
13705 100, 100, 200, 200, 0, 0, 0, NULL);
13706 ok (hparent != 0, "Failed to create parent window\n");
13707
13708 hchild = CreateWindowExA(0, "TestWindowClass", "Test child",
13709 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_DISABLED,
13710 0, 0, 0, 0, 0, 0, 0, NULL);
13711 ok (hchild != 0, "Failed to create child window\n");
13712
13713 SetParent(hchild, hparent);
13714
13715 flush_sequence();
13716 SetForegroundWindow(hother);
13717 hactive = GetForegroundWindow();
13718 ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
13719
13720 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
13721 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13722
13723 SetForegroundWindow(hdlg);
13724 test_enddialog_seq(hdlg, hchild);
13725
13726 hactive = GetForegroundWindow();
13727 ok(hactive == hchild, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
13728
13729 DestroyWindow(hdlg);
13730
13731 /* Now set WS_CHILD style flag so that it's a real child and its parent will be dialog's owner. */
13732 SetWindowLongW(hchild, GWL_STYLE, GetWindowLongW(hchild, GWL_STYLE) | WS_CHILD);
13733
13734 SetForegroundWindow(hother);
13735 hactive = GetForegroundWindow();
13736 ok(hother == hactive, "Wrong foreground window (%p != %p)\n", hother, hactive);
13737
13738 hdlg = CreateDialogParamA(0, "CLASS_TEST_DIALOG_2", hchild, test_dlg_proc, 0);
13739 ok(IsWindow(hdlg), "CreateDialogParam failed\n");
13740
13741 SetForegroundWindow(hdlg);
13742 test_enddialog_seq2(hdlg, hparent);
13743
13744 hactive = GetForegroundWindow();
13745 ok(hactive == hparent, "Wrong foreground window (active: %p, parent: %p, dlg: %p, other: %p child: %p)\n", hactive, hparent, hdlg, hother, hchild);
13746 DestroyWindow(hdlg);
13747 DestroyWindow(hchild);
13748 DestroyWindow(hparent);
13749 DestroyWindow(hother);
13750 flush_sequence();
13751
13752 UnregisterClassA(cls.lpszClassName, cls.hInstance);
13753 }
13754
13755 static void test_nullCallback(void)
13756 {
13757 HWND hwnd;
13758
13759 hwnd = CreateWindowExA(0, "TestWindowClass", "Test overlapped", WS_OVERLAPPEDWINDOW,
13760 100, 100, 200, 200, 0, 0, 0, NULL);
13761 ok (hwnd != 0, "Failed to create overlapped window\n");
13762
13763 SendMessageCallbackA(hwnd,WM_NULL,0,0,NULL,0);
13764 flush_events();
13765 DestroyWindow(hwnd);
13766 }
13767
13768 /* SetActiveWindow( 0 ) hwnd visible */
13769 static const struct message SetActiveWindowSeq0[] =
13770 {
13771 { HCBT_ACTIVATE, hook|optional },
13772 { WM_NCACTIVATE, sent|wparam, 0 },
13773 { WM_GETTEXT, sent|defwinproc|optional },
13774 { WM_ACTIVATE, sent|wparam, 0 },
13775 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
13776 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
13777 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13778 { WM_KILLFOCUS, sent|optional },
13779 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13780 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13781 { WM_NCACTIVATE, sent|wparam|optional, 1 },
13782 { WM_GETTEXT, sent|defwinproc|optional },
13783 { WM_ACTIVATE, sent|wparam|optional, 1 },
13784 { HCBT_SETFOCUS, hook|optional },
13785 { WM_KILLFOCUS, sent|defwinproc|optional },
13786 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
13787 { WM_IME_SETCONTEXT, sent|defwinproc|optional },
13788 { WM_IME_SETCONTEXT, sent|optional },
13789 { WM_IME_SETCONTEXT, sent|optional },
13790 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
13791 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13792 { WM_SETFOCUS, sent|defwinproc|optional },
13793 { WM_GETTEXT, sent|optional },
13794 { 0 }
13795 };
13796 /* SetActiveWindow( hwnd ) hwnd visible */
13797 static const struct message SetActiveWindowSeq1[] =
13798 {
13799 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13800 { 0 }
13801 };
13802 /* SetActiveWindow( popup ) hwnd visible, popup visible */
13803 static const struct message SetActiveWindowSeq2[] =
13804 {
13805 { HCBT_ACTIVATE, hook },
13806 { WM_NCACTIVATE, sent|wparam, 0 },
13807 { WM_GETTEXT, sent|defwinproc|optional },
13808 { WM_ACTIVATE, sent|wparam, 0 },
13809 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13810 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
13811 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13812 { WM_NCPAINT, sent|optional },
13813 { WM_GETTEXT, sent|defwinproc|optional },
13814 { WM_ERASEBKGND, sent|optional },
13815 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13816 { WM_NCACTIVATE, sent|wparam, 1 },
13817 { WM_GETTEXT, sent|defwinproc|optional },
13818 { WM_ACTIVATE, sent|wparam, 1 },
13819 { HCBT_SETFOCUS, hook },
13820 { WM_KILLFOCUS, sent|defwinproc },
13821 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
13822 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
13823 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
13824 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13825 { WM_SETFOCUS, sent|defwinproc },
13826 { WM_GETTEXT, sent|optional },
13827 { 0 }
13828 };
13829
13830 /* SetActiveWindow( hwnd ) hwnd not visible */
13831 static const struct message SetActiveWindowSeq3[] =
13832 {
13833 { HCBT_ACTIVATE, hook },
13834 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13835 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13836 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
13837 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOACTIVATE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13838 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13839 { WM_ACTIVATEAPP, sent|wparam, 1 },
13840 { WM_ACTIVATEAPP, sent|wparam, 1 },
13841 { WM_NCACTIVATE, sent|wparam, 1 },
13842 { WM_ACTIVATE, sent|wparam, 1 },
13843 { HCBT_SETFOCUS, hook },
13844 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
13845 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13846 { WM_SETFOCUS, sent|defwinproc },
13847 { 0 }
13848 };
13849 /* SetActiveWindow( popup ) hwnd not visible, popup not visible */
13850 static const struct message SetActiveWindowSeq4[] =
13851 {
13852 { HCBT_ACTIVATE, hook },
13853 { WM_NCACTIVATE, sent|wparam, 0 },
13854 { WM_GETTEXT, sent|defwinproc|optional },
13855 { WM_ACTIVATE, sent|wparam, 0 },
13856 { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 },
13857 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE },
13858 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE },
13859 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13860 { WM_WINDOWPOSCHANGED, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
13861 { WM_NCACTIVATE, sent|wparam, 1 },
13862 { WM_GETTEXT, sent|defwinproc|optional },
13863 { WM_ACTIVATE, sent|wparam, 1 },
13864 { HCBT_SETFOCUS, hook },
13865 { WM_KILLFOCUS, sent|defwinproc },
13866 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 0 },
13867 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
13868 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 1 },
13869 { WM_IME_NOTIFY, sent|wparam|defwinproc|optional, 2 },
13870 { WM_SETFOCUS, sent|defwinproc },
13871 { 0 }
13872 };
13873
13874
13875 static void test_SetActiveWindow(void)
13876 {
13877 HWND hwnd, popup, ret;
13878
13879 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
13880 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13881 100, 100, 200, 200, 0, 0, 0, NULL);
13882
13883 popup = CreateWindowExA(0, "TestWindowClass", "Test SetActiveWindow",
13884 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_POPUP,
13885 100, 100, 200, 200, hwnd, 0, 0, NULL);
13886
13887 ok(hwnd != 0, "Failed to create overlapped window\n");
13888 ok(popup != 0, "Failed to create popup window\n");
13889 SetForegroundWindow( popup );
13890 flush_sequence();
13891
13892 trace("SetActiveWindow(0)\n");
13893 ret = SetActiveWindow(0);
13894 ok( ret == popup, "Failed to SetActiveWindow(0)\n");
13895 ok_sequence(SetActiveWindowSeq0, "SetActiveWindow(0)", FALSE);
13896 flush_sequence();
13897
13898 trace("SetActiveWindow(hwnd), hwnd visible\n");
13899 ret = SetActiveWindow(hwnd);
13900 if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
13901 flush_sequence();
13902
13903 trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
13904 ret = SetActiveWindow(popup);
13905 ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
13906 ok_sequence(SetActiveWindowSeq2, "SetActiveWindow(popup), hwnd visible, popup visible", FALSE);
13907 flush_sequence();
13908
13909 ShowWindow(hwnd, SW_HIDE);
13910 ShowWindow(popup, SW_HIDE);
13911 flush_sequence();
13912
13913 trace("SetActiveWindow(hwnd), hwnd not visible\n");
13914 ret = SetActiveWindow(hwnd);
13915 ok( ret == NULL, "SetActiveWindow(hwnd), hwnd not visible, previous is %p\n", ret );
13916 ok_sequence(SetActiveWindowSeq3, "SetActiveWindow(hwnd), hwnd not visible", TRUE);
13917 flush_sequence();
13918
13919 trace("SetActiveWindow(popup), hwnd not visible, popup not visible\n");
13920 ret = SetActiveWindow(popup);
13921 ok( ret == hwnd, "Failed to SetActiveWindow(popup)\n");
13922 ok_sequence(SetActiveWindowSeq4, "SetActiveWindow(popup), hwnd not visible, popup not visible", TRUE);
13923 flush_sequence();
13924
13925 trace("done\n");
13926
13927 DestroyWindow(hwnd);
13928 }
13929
13930 static const struct message SetForegroundWindowSeq[] =
13931 {
13932 { WM_NCACTIVATE, sent|wparam, 0 },
13933 { WM_GETTEXT, sent|defwinproc|optional },
13934 { WM_ACTIVATE, sent|wparam, 0 },
13935 { WM_ACTIVATEAPP, sent|wparam, 0 },
13936 { WM_KILLFOCUS, sent },
13937 { WM_IME_SETCONTEXT, sent|wparam|optional, 0 },
13938 { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 },
13939 { 0 }
13940 };
13941
13942 static void test_SetForegroundWindow(void)
13943 {
13944 HWND hwnd;
13945
13946 hwnd = CreateWindowExA(0, "TestWindowClass", "Test SetForegroundWindow",
13947 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
13948 100, 100, 200, 200, 0, 0, 0, NULL);
13949 ok (hwnd != 0, "Failed to create overlapped window\n");
13950 SetForegroundWindow( hwnd );
13951 flush_sequence();
13952
13953 trace("SetForegroundWindow( 0 )\n");
13954 SetForegroundWindow( 0 );
13955 ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
13956 trace("SetForegroundWindow( GetDesktopWindow() )\n");
13957 SetForegroundWindow( GetDesktopWindow() );
13958 ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
13959 "foreground top level window", FALSE);
13960 trace("done\n");
13961
13962 DestroyWindow(hwnd);
13963 }
13964
13965 static DWORD get_input_codepage( void )
13966 {
13967 DWORD cp;
13968 int ret;
13969 HKL hkl = GetKeyboardLayout( 0 );
13970
13971 ret = GetLocaleInfoW( LOWORD(hkl), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
13972 (WCHAR *)&cp, sizeof(cp) / sizeof(WCHAR) );
13973 if (!ret) cp = CP_ACP;
13974 return cp;
13975 }
13976
13977 static void test_dbcs_wm_char(void)
13978 {
13979 BYTE dbch[2];
13980 WCHAR wch, bad_wch;
13981 HWND hwnd, hwnd2;
13982 MSG msg;
13983 DWORD time;
13984 POINT pt;
13985 DWORD_PTR res;
13986 CPINFOEXA cpinfo;
13987 UINT i, j, k;
13988 struct message wmCharSeq[2];
13989 BOOL ret;
13990 DWORD cp = get_input_codepage();
13991
13992 if (!pGetCPInfoExA)
13993 {
13994 win_skip("GetCPInfoExA is not available\n");
13995 return;
13996 }
13997
13998 pGetCPInfoExA( cp, 0, &cpinfo );
13999 if (cpinfo.MaxCharSize != 2)
14000 {
14001 skip( "Skipping DBCS WM_CHAR test in SBCS codepage '%s'\n", cpinfo.CodePageName );
14002 return;
14003 }
14004
14005 dbch[0] = dbch[1] = 0;
14006 wch = 0;
14007 bad_wch = cpinfo.UnicodeDefaultChar;
14008 for (i = 0; !wch && i < MAX_LEADBYTES && cpinfo.LeadByte[i]; i += 2)
14009 for (j = cpinfo.LeadByte[i]; !wch && j <= cpinfo.LeadByte[i+1]; j++)
14010 for (k = 128; k <= 255; k++)
14011 {
14012 char str[2];
14013 WCHAR wstr[2];
14014 str[0] = j;
14015 str[1] = k;
14016 if (MultiByteToWideChar( cp, 0, str, 2, wstr, 2 ) == 1 &&
14017 WideCharToMultiByte( cp, 0, wstr, 1, str, 2, NULL, NULL ) == 2 &&
14018 (BYTE)str[0] == j && (BYTE)str[1] == k &&
14019 HIBYTE(wstr[0]) && HIBYTE(wstr[0]) != 0xff)
14020 {
14021 dbch[0] = j;
14022 dbch[1] = k;
14023 wch = wstr[0];
14024 break;
14025 }
14026 }
14027
14028 if (!wch)
14029 {
14030 skip( "Skipping DBCS WM_CHAR test, no appropriate char found\n" );
14031 return;
14032 }
14033 trace( "using dbcs char %02x,%02x wchar %04x bad wchar %04x codepage '%s'\n",
14034 dbch[0], dbch[1], wch, bad_wch, cpinfo.CodePageName );
14035
14036 hwnd = CreateWindowExW(0, testWindowClassW, NULL,
14037 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
14038 hwnd2 = CreateWindowExW(0, testWindowClassW, NULL,
14039 WS_OVERLAPPEDWINDOW, 100, 100, 200, 200, 0, 0, 0, NULL);
14040 ok (hwnd != 0, "Failed to create overlapped window\n");
14041 ok (hwnd2 != 0, "Failed to create overlapped window\n");
14042 flush_sequence();
14043
14044 memset( wmCharSeq, 0, sizeof(wmCharSeq) );
14045 wmCharSeq[0].message = WM_CHAR;
14046 wmCharSeq[0].flags = sent|wparam;
14047 wmCharSeq[0].wParam = wch;
14048
14049 /* posted message */
14050 PostMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14051 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14052 ok( !ret, "got message %x\n", msg.message );
14053 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14054 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14055 ok( ret, "no message\n" );
14056 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14057 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14058 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14059 ok( !ret, "got message %x\n", msg.message );
14060
14061 /* posted thread message */
14062 PostThreadMessageA( GetCurrentThreadId(), WM_CHAR, dbch[0], 0 );
14063 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14064 ok( !ret, "got message %x\n", msg.message );
14065 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14066 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14067 ok( ret, "no message\n" );
14068 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14069 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14070 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14071 ok( !ret, "got message %x\n", msg.message );
14072
14073 /* sent message */
14074 flush_sequence();
14075 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14076 ok_sequence( WmEmptySeq, "no messages", FALSE );
14077 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14078 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14079 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14080 ok( !ret, "got message %x\n", msg.message );
14081
14082 /* sent message with timeout */
14083 flush_sequence();
14084 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
14085 ok_sequence( WmEmptySeq, "no messages", FALSE );
14086 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
14087 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14088 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14089 ok( !ret, "got message %x\n", msg.message );
14090
14091 /* sent message with timeout and callback */
14092 flush_sequence();
14093 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[0], 0, SMTO_NORMAL, 0, &res );
14094 ok_sequence( WmEmptySeq, "no messages", FALSE );
14095 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
14096 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14097 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14098 ok( !ret, "got message %x\n", msg.message );
14099
14100 /* sent message with callback */
14101 flush_sequence();
14102 SendNotifyMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14103 ok_sequence( WmEmptySeq, "no messages", FALSE );
14104 SendMessageCallbackA( hwnd, WM_CHAR, dbch[1], 0, NULL, 0 );
14105 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14106 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14107 ok( !ret, "got message %x\n", msg.message );
14108
14109 /* direct window proc call */
14110 flush_sequence();
14111 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14112 ok_sequence( WmEmptySeq, "no messages", FALSE );
14113 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14114 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14115
14116 /* dispatch message */
14117 msg.hwnd = hwnd;
14118 msg.message = WM_CHAR;
14119 msg.wParam = dbch[0];
14120 msg.lParam = 0;
14121 DispatchMessageA( &msg );
14122 ok_sequence( WmEmptySeq, "no messages", FALSE );
14123 msg.wParam = dbch[1];
14124 DispatchMessageA( &msg );
14125 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14126
14127 /* window handle is irrelevant */
14128 flush_sequence();
14129 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14130 ok_sequence( WmEmptySeq, "no messages", FALSE );
14131 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14132 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14133 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14134 ok( !ret, "got message %x\n", msg.message );
14135
14136 /* interleaved post and send */
14137 flush_sequence();
14138 PostMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14139 SendMessageA( hwnd2, WM_CHAR, dbch[0], 0 );
14140 ok_sequence( WmEmptySeq, "no messages", FALSE );
14141 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14142 ok( !ret, "got message %x\n", msg.message );
14143 PostMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14144 ok_sequence( WmEmptySeq, "no messages", FALSE );
14145 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14146 ok( ret, "no message\n" );
14147 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14148 ok( msg.wParam == wch, "bad wparam %lx/%x\n", msg.wParam, wch );
14149 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14150 ok( !ret, "got message %x\n", msg.message );
14151 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14152 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14153 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14154 ok( !ret, "got message %x\n", msg.message );
14155
14156 /* interleaved sent message and winproc */
14157 flush_sequence();
14158 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14159 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14160 ok_sequence( WmEmptySeq, "no messages", FALSE );
14161 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14162 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14163 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14164 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14165
14166 /* interleaved winproc and dispatch */
14167 msg.hwnd = hwnd;
14168 msg.message = WM_CHAR;
14169 msg.wParam = dbch[0];
14170 msg.lParam = 0;
14171 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[0], 0 );
14172 DispatchMessageA( &msg );
14173 ok_sequence( WmEmptySeq, "no messages", FALSE );
14174 msg.wParam = dbch[1];
14175 DispatchMessageA( &msg );
14176 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14177 CallWindowProcA( (WNDPROC)GetWindowLongPtrA( hwnd, GWLP_WNDPROC ), hwnd, WM_CHAR, dbch[1], 0 );
14178 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14179
14180 /* interleaved sends */
14181 flush_sequence();
14182 SendMessageA( hwnd, WM_CHAR, dbch[0], 0 );
14183 SendMessageCallbackA( hwnd, WM_CHAR, dbch[0], 0, NULL, 0 );
14184 ok_sequence( WmEmptySeq, "no messages", FALSE );
14185 SendMessageTimeoutA( hwnd, WM_CHAR, dbch[1], 0, SMTO_NORMAL, 0, &res );
14186 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14187 SendMessageA( hwnd, WM_CHAR, dbch[1], 0 );
14188 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14189
14190 /* dbcs WM_CHAR */
14191 flush_sequence();
14192 SendMessageA( hwnd2, WM_CHAR, (dbch[1] << 8) | dbch[0], 0 );
14193 ok_sequence( wmCharSeq, "Unicode WM_CHAR", FALSE );
14194 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14195 ok( !ret, "got message %x\n", msg.message );
14196
14197 /* other char messages are not magic */
14198 PostMessageA( hwnd, WM_SYSCHAR, dbch[0], 0 );
14199 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14200 ok( ret, "no message\n" );
14201 ok( msg.message == WM_SYSCHAR, "unexpected message %x\n", msg.message );
14202 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
14203 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14204 ok( !ret, "got message %x\n", msg.message );
14205 PostMessageA( hwnd, WM_DEADCHAR, dbch[0], 0 );
14206 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14207 ok( ret, "no message\n" );
14208 ok( msg.message == WM_DEADCHAR, "unexpected message %x\n", msg.message );
14209 ok( msg.wParam == bad_wch, "bad wparam %lx/%x\n", msg.wParam, bad_wch );
14210 ret = PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE );
14211 ok( !ret, "got message %x\n", msg.message );
14212
14213 /* test retrieving messages */
14214
14215 PostMessageW( hwnd, WM_CHAR, wch, 0 );
14216 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14217 ok( ret, "no message\n" );
14218 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14219 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14220 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14221 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14222 ok( ret, "no message\n" );
14223 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14224 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14225 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14226 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14227 ok( !ret, "got message %x\n", msg.message );
14228
14229 /* message filters */
14230 PostMessageW( hwnd, WM_CHAR, wch, 0 );
14231 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14232 ok( ret, "no message\n" );
14233 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14234 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14235 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14236 /* message id is filtered, hwnd is not */
14237 ret = PeekMessageA( &msg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE );
14238 ok( !ret, "no message\n" );
14239 ret = PeekMessageA( &msg, hwnd2, 0, 0, PM_REMOVE );
14240 ok( ret, "no message\n" );
14241 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14242 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14243 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14244 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14245 ok( !ret, "got message %x\n", msg.message );
14246
14247 /* mixing GetMessage and PostMessage */
14248 PostMessageW( hwnd, WM_CHAR, wch, 0xbeef );
14249 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
14250 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14251 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14252 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14253 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
14254 time = msg.time;
14255 pt = msg.pt;
14256 ok( time - GetTickCount() <= 100, "bad time %x\n", msg.time );
14257 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14258 ok( ret, "no message\n" );
14259 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14260 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14261 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14262 ok( msg.lParam == 0xbeef, "bad lparam %lx\n", msg.lParam );
14263 ok( msg.time == time, "bad time %x/%x\n", msg.time, time );
14264 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 );
14265 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14266 ok( !ret, "got message %x\n", msg.message );
14267
14268 /* without PM_REMOVE */
14269 PostMessageW( hwnd, WM_CHAR, wch, 0 );
14270 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
14271 ok( ret, "no message\n" );
14272 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14273 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14274 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14275 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14276 ok( ret, "no message\n" );
14277 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14278 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14279 ok( msg.wParam == dbch[0], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14280 ret = PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
14281 ok( ret, "no message\n" );
14282 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14283 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14284 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14285 ret = PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
14286 ok( ret, "no message\n" );
14287 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14288 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14289 ok( msg.wParam == dbch[1], "bad wparam %lx/%x\n", msg.wParam, dbch[0] );
14290 ret = PeekMessageA( &msg, hwnd, 0, 0, PM_REMOVE );
14291 ok( !ret, "got message %x\n", msg.message );
14292
14293 DestroyWindow(hwnd);
14294 DestroyWindow(hwnd2);
14295 }
14296
14297 static void test_unicode_wm_char(void)
14298 {
14299 HWND hwnd;
14300 MSG msg;
14301 struct message seq[2];
14302 HKL hkl_orig, hkl_greek;
14303 DWORD cp;
14304 LCID thread_locale;
14305
14306 hkl_orig = GetKeyboardLayout( 0 );
14307 GetLocaleInfoW( LOWORD( hkl_orig ), LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER, (WCHAR*)&cp, sizeof(cp) / sizeof(WCHAR) );
14308 if (cp != 1252)
14309 {
14310 skip( "Default codepage %d\n", cp );
14311 return;
14312 }
14313
14314 hkl_greek = LoadKeyboardLayoutA( "00000408", 0 );
14315 if (!hkl_greek || hkl_greek == hkl_orig /* win2k */)
14316 {
14317 skip( "Unable to load Greek keyboard layout\n" );
14318 return;
14319 }
14320
14321 hwnd = CreateWindowExW( 0, testWindowClassW, NULL, WS_OVERLAPPEDWINDOW,
14322 100, 100, 200, 200, 0, 0, 0, NULL );
14323 flush_sequence();
14324
14325 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14326
14327 while (GetMessageW( &msg, hwnd, 0, 0 ))
14328 {
14329 if (!ignore_message( msg.message )) break;
14330 }
14331
14332 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14333 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14334 ok( msg.wParam == 0x3b1, "bad wparam %lx\n", msg.wParam );
14335 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14336
14337 DispatchMessageW( &msg );
14338
14339 memset( seq, 0, sizeof(seq) );
14340 seq[0].message = WM_CHAR;
14341 seq[0].flags = sent|wparam;
14342 seq[0].wParam = 0x3b1;
14343
14344 ok_sequence( seq, "unicode WM_CHAR", FALSE );
14345
14346 flush_sequence();
14347
14348 /* greek alpha -> 'a' in cp1252 */
14349 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14350
14351 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
14352 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14353 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14354 ok( msg.wParam == 0x61, "bad wparam %lx\n", msg.wParam );
14355 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14356
14357 DispatchMessageA( &msg );
14358
14359 seq[0].wParam = 0x61;
14360 ok_sequence( seq, "unicode WM_CHAR", FALSE );
14361
14362 thread_locale = GetThreadLocale();
14363 ActivateKeyboardLayout( hkl_greek, 0 );
14364 ok( GetThreadLocale() == thread_locale, "locale changed from %08x to %08x\n",
14365 thread_locale, GetThreadLocale() );
14366
14367 flush_sequence();
14368
14369 /* greek alpha -> 0xe1 in cp1253 */
14370 PostMessageW( hwnd, WM_CHAR, 0x3b1, 0 );
14371
14372 ok( GetMessageA( &msg, hwnd, 0, 0 ), "no message\n" );
14373 ok( msg.hwnd == hwnd, "unexpected hwnd %p\n", msg.hwnd );
14374 ok( msg.message == WM_CHAR, "unexpected message %x\n", msg.message );
14375 ok( msg.wParam == 0xe1, "bad wparam %lx\n", msg.wParam );
14376 ok( msg.lParam == 0, "bad lparam %lx\n", msg.lParam );
14377
14378 DispatchMessageA( &msg );
14379
14380 seq[0].wParam = 0x3b1;
14381 ok_sequence( seq, "unicode WM_CHAR", FALSE );
14382
14383 DestroyWindow( hwnd );
14384 ActivateKeyboardLayout( hkl_orig, 0 );
14385 UnloadKeyboardLayout( hkl_greek );
14386 }
14387
14388 #define ID_LISTBOX 0x000f
14389
14390 static const struct message wm_lb_setcursel_0[] =
14391 {
14392 { LB_SETCURSEL, sent|wparam|lparam, 0, 0 },
14393 { WM_CTLCOLORLISTBOX, sent|parent },
14394 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
14395 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14396 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14397 { 0 }
14398 };
14399 static const struct message wm_lb_setcursel_1[] =
14400 {
14401 { LB_SETCURSEL, sent|wparam|lparam, 1, 0 },
14402 { WM_CTLCOLORLISTBOX, sent|parent },
14403 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000020f2 },
14404 { WM_CTLCOLORLISTBOX, sent|parent },
14405 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000121f2 },
14406 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
14407 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 2 },
14408 { 0 }
14409 };
14410 static const struct message wm_lb_setcursel_2[] =
14411 {
14412 { LB_SETCURSEL, sent|wparam|lparam, 2, 0 },
14413 { WM_CTLCOLORLISTBOX, sent|parent },
14414 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000021f2 },
14415 { WM_CTLCOLORLISTBOX, sent|parent },
14416 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000122f2 },
14417 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
14418 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
14419 { 0 }
14420 };
14421 static const struct message wm_lb_click_0[] =
14422 {
14423 { WM_LBUTTONDOWN, sent|wparam|lparam, 0, MAKELPARAM(1,1) },
14424 { HCBT_SETFOCUS, hook },
14425 { WM_KILLFOCUS, sent|parent },
14426 { WM_IME_SETCONTEXT, sent|wparam|optional|parent, 0 },
14427 { WM_IME_SETCONTEXT, sent|wparam|defwinproc|optional, 1 },
14428 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
14429 { WM_SETFOCUS, sent|defwinproc },
14430
14431 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001142f2 },
14432 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SETFOCUS) },
14433 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 3 },
14434 { WM_LBTRACKPOINT, sent|wparam|lparam|parent, 0, MAKELPARAM(1,1) },
14435 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
14436
14437 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000142f2 },
14438 { WM_CTLCOLORLISTBOX, sent|parent },
14439 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000022f2 },
14440 { WM_CTLCOLORLISTBOX, sent|parent },
14441 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x000120f2 },
14442 { WM_DRAWITEM, sent|wparam|lparam|parent, ID_LISTBOX, 0x001140f2 },
14443
14444 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14445 { EVENT_OBJECT_SELECTION, winevent_hook|wparam|lparam, OBJID_CLIENT, 1 },
14446
14447 { WM_LBUTTONUP, sent|wparam|lparam, 0, 0 },
14448 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
14449 { WM_CAPTURECHANGED, sent|wparam|lparam|defwinproc, 0, 0 },
14450 { WM_COMMAND, sent|wparam|parent, MAKEWPARAM(ID_LISTBOX, LBN_SELCHANGE) },
14451 { 0 }
14452 };
14453 static const struct message wm_lb_deletestring[] =
14454 {
14455 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
14456 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
14457 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14458 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14459 { 0 }
14460 };
14461 static const struct message wm_lb_deletestring_reset[] =
14462 {
14463 { LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
14464 { LB_RESETCONTENT, sent|wparam|lparam|defwinproc|optional, 0, 0 },
14465 { WM_DELETEITEM, sent|wparam|parent|optional, ID_LISTBOX, 0 },
14466 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14467 { WM_DRAWITEM, sent|wparam|parent|optional, ID_LISTBOX },
14468 { 0 }
14469 };
14470 static const struct message wm_lb_addstring[] =
14471 {
14472 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
14473 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed },
14474 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
14475 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee },
14476 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
14477 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef },
14478 { 0 }
14479 };
14480 static const struct message wm_lb_addstring_sort[] =
14481 {
14482 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ed },
14483 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf0f2, 0xf30604ed },
14484 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ee },
14485 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ee },
14486 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf1f2, 0xf30604ee },
14487 { LB_ADDSTRING, sent|wparam|lparam, 0, 0xf30604ef },
14488 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ed, 0xf30604ef },
14489 { WM_COMPAREITEM, sent|wparam|lparam|parent, 0xf30604ee, 0xf30604ef },
14490 { WM_MEASUREITEM, sent|wparam|lparam|parent, 0xf2f2, 0xf30604ef },
14491 { 0 }
14492 };
14493
14494 #define check_lb_state(a1, a2, a3, a4, a5) check_lb_state_dbg(a1, a2, a3, a4, a5, __LINE__)
14495
14496 static LRESULT (WINAPI *listbox_orig_proc)(HWND, UINT, WPARAM, LPARAM);
14497
14498 static LRESULT WINAPI listbox_hook_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
14499 {
14500 static LONG defwndproc_counter = 0;
14501 LRESULT ret;
14502 struct recvd_message msg;
14503
14504 /* do not log painting messages */
14505 if (message != WM_PAINT &&
14506 message != WM_NCPAINT &&
14507 message != WM_SYNCPAINT &&
14508 message != WM_ERASEBKGND &&
14509 message != WM_NCHITTEST &&
14510 message != WM_GETTEXT &&
14511 !ignore_message( message ))
14512 {
14513 msg.hwnd = hwnd;
14514 msg.message = message;
14515 msg.flags = sent|wparam|lparam;
14516 if (defwndproc_counter) msg.flags |= defwinproc;
14517 msg.wParam = wp;
14518 if (message == LB_ADDSTRING)
14519 msg.lParam = lp ? hash_Ly((const char *)lp) : 0;
14520 else
14521 msg.lParam = lp;
14522 msg.descr = "listbox";
14523 add_message(&msg);
14524 }
14525
14526 defwndproc_counter++;
14527 ret = CallWindowProcA(listbox_orig_proc, hwnd, message, wp, lp);
14528 defwndproc_counter--;
14529
14530 return ret;
14531 }
14532
14533 static void check_lb_state_dbg(HWND listbox, int count, int cur_sel,
14534 int caret_index, int top_index, int line)
14535 {
14536 LRESULT ret;
14537
14538 /* calling an orig proc helps to avoid unnecessary message logging */
14539 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCOUNT, 0, 0);
14540 ok_(__FILE__, line)(ret == count, "expected count %d, got %ld\n", count, ret);
14541 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCURSEL, 0, 0);
14542 ok_(__FILE__, line)(ret == cur_sel, "expected cur sel %d, got %ld\n", cur_sel, ret);
14543 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETCARETINDEX, 0, 0);
14544 ok_(__FILE__, line)(ret == caret_index ||
14545 broken(cur_sel == -1 && caret_index == 0 && ret == -1), /* nt4 */
14546 "expected caret index %d, got %ld\n", caret_index, ret);
14547 ret = CallWindowProcA(listbox_orig_proc, listbox, LB_GETTOPINDEX, 0, 0);
14548 ok_(__FILE__, line)(ret == top_index, "expected top index %d, got %ld\n", top_index, ret);
14549 }
14550
14551 static void test_listbox_messages(void)
14552 {
14553 HWND parent, listbox;
14554 LRESULT ret;
14555
14556 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14557 100, 100, 200, 200, 0, 0, 0, NULL);
14558 /* with LBS_HASSTRINGS */
14559 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
14560 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
14561 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
14562 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
14563
14564 check_lb_state(listbox, 0, LB_ERR, 0, 0);
14565
14566 flush_sequence();
14567
14568 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
14569 ok(ret == 0, "expected 0, got %ld\n", ret);
14570 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
14571 ok(ret == 1, "expected 1, got %ld\n", ret);
14572 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
14573 ok(ret == 2, "expected 2, got %ld\n", ret);
14574
14575 ok_sequence(wm_lb_addstring, "LB_ADDSTRING", FALSE);
14576 check_lb_state(listbox, 3, LB_ERR, 0, 0);
14577
14578 flush_sequence();
14579
14580 log_all_parent_messages++;
14581
14582 trace("selecting item 0\n");
14583 ret = SendMessageA(listbox, LB_SETCURSEL, 0, 0);
14584 ok(ret == 0, "expected 0, got %ld\n", ret);
14585 ok_sequence(wm_lb_setcursel_0, "LB_SETCURSEL 0", FALSE );
14586 check_lb_state(listbox, 3, 0, 0, 0);
14587 flush_sequence();
14588
14589 trace("selecting item 1\n");
14590 ret = SendMessageA(listbox, LB_SETCURSEL, 1, 0);
14591 ok(ret == 1, "expected 1, got %ld\n", ret);
14592 ok_sequence(wm_lb_setcursel_1, "LB_SETCURSEL 1", FALSE );
14593 check_lb_state(listbox, 3, 1, 1, 0);
14594
14595 trace("selecting item 2\n");
14596 ret = SendMessageA(listbox, LB_SETCURSEL, 2, 0);
14597 ok(ret == 2, "expected 2, got %ld\n", ret);
14598 ok_sequence(wm_lb_setcursel_2, "LB_SETCURSEL 2", FALSE );
14599 check_lb_state(listbox, 3, 2, 2, 0);
14600
14601 trace("clicking on item 0\n");
14602 ret = SendMessageA(listbox, WM_LBUTTONDOWN, 0, MAKELPARAM(1, 1));
14603 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
14604 ret = SendMessageA(listbox, WM_LBUTTONUP, 0, 0);
14605 ok(ret == LB_OKAY, "expected LB_OKAY, got %ld\n", ret);
14606 ok_sequence(wm_lb_click_0, "WM_LBUTTONDOWN 0", FALSE );
14607 check_lb_state(listbox, 3, 0, 0, 0);
14608 flush_sequence();
14609
14610 trace("deleting item 0\n");
14611 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14612 ok(ret == 2, "expected 2, got %ld\n", ret);
14613 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
14614 check_lb_state(listbox, 2, -1, 0, 0);
14615 flush_sequence();
14616
14617 trace("deleting item 0\n");
14618 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14619 ok(ret == 1, "expected 1, got %ld\n", ret);
14620 ok_sequence(wm_lb_deletestring, "LB_DELETESTRING 0", FALSE );
14621 check_lb_state(listbox, 1, -1, 0, 0);
14622 flush_sequence();
14623
14624 trace("deleting item 0\n");
14625 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14626 ok(ret == 0, "expected 0, got %ld\n", ret);
14627 ok_sequence(wm_lb_deletestring_reset, "LB_DELETESTRING 0", FALSE );
14628 check_lb_state(listbox, 0, -1, 0, 0);
14629 flush_sequence();
14630
14631 trace("deleting item 0\n");
14632 ret = SendMessageA(listbox, LB_DELETESTRING, 0, 0);
14633 ok(ret == LB_ERR, "expected LB_ERR, got %ld\n", ret);
14634 check_lb_state(listbox, 0, -1, 0, 0);
14635 flush_sequence();
14636
14637 log_all_parent_messages--;
14638
14639 DestroyWindow(listbox);
14640
14641 /* with LBS_SORT and without LBS_HASSTRINGS */
14642 listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, "ListBox", NULL,
14643 WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_SORT | WS_VISIBLE,
14644 10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
14645 listbox_orig_proc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (ULONG_PTR)listbox_hook_proc);
14646
14647 check_lb_state(listbox, 0, LB_ERR, 0, 0);
14648
14649 flush_sequence();
14650
14651 log_all_parent_messages++;
14652
14653 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
14654 ok(ret == 0, "expected 0, got %ld\n", ret);
14655 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
14656 ok(ret == 1, "expected 1, got %ld\n", ret);
14657 ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
14658 ok(ret == 2, "expected 2, got %ld\n", ret);
14659
14660 ok_sequence(wm_lb_addstring_sort, "LB_ADDSTRING", FALSE);
14661 check_lb_state(listbox, 3, LB_ERR, 0, 0);
14662
14663 log_all_parent_messages--;
14664
14665 DestroyWindow(listbox);
14666 DestroyWindow(parent);
14667 }
14668
14669 /*************************** Menu test ******************************/
14670 static const struct message wm_popup_menu_1[] =
14671 {
14672 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14673 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14674 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0x20000001 },
14675 { WM_SYSKEYDOWN, sent|wparam|lparam, 'E', 0x20000001 },
14676 { WM_SYSCHAR, sent|wparam|lparam, 'e', 0x20000001 },
14677 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'e' },
14678 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14679 { WM_INITMENU, sent|lparam, 0, 0 },
14680 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(1,MF_HILITE|MF_POPUP) },
14681 { WM_INITMENUPOPUP, sent|lparam, 0, 1 },
14682 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't create a window */
14683 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(200,MF_HILITE) },
14684 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'E', 0xf0000001 },
14685 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
14686 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001, 0, 0x40000000 },
14687 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't create a window */
14688 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14689 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14690 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14691 { WM_MENUCOMMAND, sent }, /* |wparam, 200 - Win9x */
14692 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
14693 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
14694 { 0 }
14695 };
14696 static const struct message wm_popup_menu_2[] =
14697 {
14698 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14699 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14700 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
14701 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
14702 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
14703 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
14704 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14705 { WM_INITMENU, sent|lparam, 0, 0 },
14706 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
14707 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
14708 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
14709 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
14710 { HCBT_CREATEWND, hook },
14711 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
14712 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
14713 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
14714 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
14715 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
14716 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
14717 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
14718 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
14719 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
14720 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
14721 { HCBT_DESTROYWND, hook },
14722 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14723 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
14724 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14725 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14726 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14727 { WM_MENUCOMMAND, sent }, /* |wparam, 100 - Win9x */
14728 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
14729 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
14730 { 0 }
14731 };
14732 static const struct message wm_popup_menu_3[] =
14733 {
14734 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14735 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14736 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0x20000001 },
14737 { WM_SYSKEYDOWN, sent|wparam|lparam, 'F', 0x20000001 },
14738 { WM_SYSCHAR, sent|wparam|lparam, 'f', 0x20000001 },
14739 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'f' },
14740 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14741 { WM_INITMENU, sent|lparam, 0, 0 },
14742 { WM_MENUSELECT, sent|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) },
14743 { WM_INITMENUPOPUP, sent|lparam, 0, 0 },
14744 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(0,MF_HILITE|MF_POPUP) }, /* Win9x */
14745 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x */
14746 { HCBT_CREATEWND, hook },
14747 { WM_MENUSELECT, sent }, /*|wparam, MAKEWPARAM(0,MF_HILITE|MF_POPUP) - XP
14748 |wparam, MAKEWPARAM(100,MF_HILITE) - Win9x */
14749 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'F', 0xf0000001 },
14750 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xd0000001 },
14751 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0x10000001 },
14752 { WM_INITMENUPOPUP, sent|lparam|optional, 0, 0 }, /* Win9x doesn't send it */
14753 { HCBT_CREATEWND, hook|optional }, /* Win9x doesn't send it */
14754 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(100,MF_HILITE) },
14755 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RIGHT, 0xd0000001 },
14756 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0x10000001 },
14757 { HCBT_DESTROYWND, hook },
14758 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14759 { HCBT_DESTROYWND, hook|optional }, /* Win9x doesn't send it */
14760 { WM_UNINITMENUPOPUP, sent|lparam, 0, 0 },
14761 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14762 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14763 { WM_COMMAND, sent|wparam|lparam, 100, 0 },
14764 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_RETURN, 0xc0000001 },
14765 { WM_KEYUP, sent|wparam|lparam, VK_RETURN, 0xc0000001 },
14766 { 0 }
14767 };
14768
14769 static const struct message wm_single_menu_item[] =
14770 {
14771 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0x20000001 },
14772 { WM_SYSKEYDOWN, sent|wparam|lparam, VK_MENU, 0x20000001 },
14773 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0x20000001 },
14774 { WM_SYSKEYDOWN, sent|wparam|lparam, 'Q', 0x20000001 },
14775 { WM_SYSCHAR, sent|wparam|lparam, 'q', 0x20000001 },
14776 { HCBT_SYSCOMMAND, hook|wparam|lparam, SC_KEYMENU, 'q' },
14777 { WM_ENTERMENULOOP, sent|wparam|lparam, 0, 0 },
14778 { WM_INITMENU, sent|lparam, 0, 0 },
14779 { WM_MENUSELECT, sent|wparam|optional, MAKEWPARAM(300,MF_HILITE) },
14780 { WM_MENUSELECT, sent|wparam|lparam, MAKEWPARAM(0,0xffff), 0 },
14781 { WM_EXITMENULOOP, sent|wparam|lparam, 0, 0 },
14782 { WM_MENUCOMMAND, sent },
14783 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 'Q', 0xe0000001 },
14784 { WM_SYSKEYUP, sent|wparam|lparam, 'Q', 0xe0000001 },
14785 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_MENU, 0xc0000001 },
14786 { WM_KEYUP, sent|wparam|lparam, VK_MENU, 0xc0000001 },
14787
14788 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 1 },
14789 { WM_KEYDOWN, sent|wparam|lparam, VK_ESCAPE, 1 },
14790 { WM_CHAR, sent|wparam|lparam, VK_ESCAPE, 0x00000001 },
14791 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_ESCAPE, 0xc0000001 },
14792 { WM_KEYUP, sent|wparam|lparam, VK_ESCAPE, 0xc0000001 },
14793 { 0 }
14794 };
14795
14796 static LRESULT WINAPI parent_menu_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp)
14797 {
14798 if (message == WM_ENTERIDLE ||
14799 message == WM_INITMENU ||
14800 message == WM_INITMENUPOPUP ||
14801 message == WM_MENUSELECT ||
14802 message == WM_PARENTNOTIFY ||
14803 message == WM_ENTERMENULOOP ||
14804 message == WM_EXITMENULOOP ||
14805 message == WM_UNINITMENUPOPUP ||
14806 message == WM_KEYDOWN ||
14807 message == WM_KEYUP ||
14808 message == WM_CHAR ||
14809 message == WM_SYSKEYDOWN ||
14810 message == WM_SYSKEYUP ||
14811 message == WM_SYSCHAR ||
14812 message == WM_COMMAND ||
14813 message == WM_MENUCOMMAND)
14814 {
14815 struct recvd_message msg;
14816
14817 msg.hwnd = hwnd;
14818 msg.message = message;
14819 msg.flags = sent|wparam|lparam;
14820 msg.wParam = wp;
14821 msg.lParam = lp;
14822 msg.descr = "parent_menu_proc";
14823 add_message(&msg);
14824 }
14825
14826 return DefWindowProcA(hwnd, message, wp, lp);
14827 }
14828
14829 static void set_menu_style(HMENU hmenu, DWORD style)
14830 {
14831 MENUINFO mi;
14832 BOOL ret;
14833
14834 mi.cbSize = sizeof(mi);
14835 mi.fMask = MIM_STYLE;
14836 mi.dwStyle = style;
14837 SetLastError(0xdeadbeef);
14838 ret = pSetMenuInfo(hmenu, &mi);
14839 ok(ret, "SetMenuInfo error %u\n", GetLastError());
14840 }
14841
14842 static DWORD get_menu_style(HMENU hmenu)
14843 {
14844 MENUINFO mi;
14845 BOOL ret;
14846
14847 mi.cbSize = sizeof(mi);
14848 mi.fMask = MIM_STYLE;
14849 mi.dwStyle = 0;
14850 SetLastError(0xdeadbeef);
14851 ret = pGetMenuInfo(hmenu, &mi);
14852 ok(ret, "GetMenuInfo error %u\n", GetLastError());
14853
14854 return mi.dwStyle;
14855 }
14856
14857 static void test_menu_messages(void)
14858 {
14859 MSG msg;
14860 WNDCLASSA cls;
14861 HMENU hmenu, hmenu_popup;
14862 HWND hwnd;
14863 DWORD style;
14864
14865 if (!pGetMenuInfo || !pSetMenuInfo)
14866 {
14867 win_skip("GetMenuInfo and/or SetMenuInfo are not available\n");
14868 return;
14869 }
14870 cls.style = 0;
14871 cls.lpfnWndProc = parent_menu_proc;
14872 cls.cbClsExtra = 0;
14873 cls.cbWndExtra = 0;
14874 cls.hInstance = GetModuleHandleA(0);
14875 cls.hIcon = 0;
14876 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
14877 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
14878 cls.lpszMenuName = NULL;
14879 cls.lpszClassName = "TestMenuClass";
14880 UnregisterClassA(cls.lpszClassName, cls.hInstance);
14881 if (!RegisterClassA(&cls)) assert(0);
14882
14883 SetLastError(0xdeadbeef);
14884 hwnd = CreateWindowExA(0, "TestMenuClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
14885 100, 100, 200, 200, 0, 0, 0, NULL);
14886 ok(hwnd != 0, "LoadMenuA error %u\n", GetLastError());
14887
14888 SetLastError(0xdeadbeef);
14889 hmenu = LoadMenuA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(1));
14890 ok(hmenu != 0, "LoadMenuA error %u\n", GetLastError());
14891
14892 SetMenu(hwnd, hmenu);
14893 SetForegroundWindow( hwnd );
14894 flush_events();
14895
14896 set_menu_style(hmenu, MNS_NOTIFYBYPOS);
14897 style = get_menu_style(hmenu);
14898 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
14899
14900 hmenu_popup = GetSubMenu(hmenu, 0);
14901 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
14902 style = get_menu_style(hmenu_popup);
14903 ok(style == 0, "expected 0, got %u\n", style);
14904
14905 hmenu_popup = GetSubMenu(hmenu_popup, 0);
14906 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
14907 style = get_menu_style(hmenu_popup);
14908 ok(style == 0, "expected 0, got %u\n", style);
14909
14910 /* Alt+E, Enter */
14911 trace("testing a popup menu command\n");
14912 flush_sequence();
14913 keybd_event(VK_MENU, 0, 0, 0);
14914 keybd_event('E', 0, 0, 0);
14915 keybd_event('E', 0, KEYEVENTF_KEYUP, 0);
14916 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
14917 keybd_event(VK_RETURN, 0, 0, 0);
14918 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
14919 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14920 {
14921 TranslateMessage(&msg);
14922 DispatchMessageA(&msg);
14923 }
14924 if (!sequence_cnt) /* we didn't get any message */
14925 {
14926 skip( "queuing key events not supported\n" );
14927 goto done;
14928 }
14929 /* win98 queues only a WM_KEYUP and doesn't start menu tracking */
14930 if (sequence[0].message == WM_KEYUP && sequence[0].wParam == VK_MENU)
14931 {
14932 win_skip( "menu tracking through VK_MENU not supported\n" );
14933 goto done;
14934 }
14935 ok_sequence(wm_popup_menu_1, "popup menu command", FALSE);
14936
14937 /* Alt+F, Right, Enter */
14938 trace("testing submenu of a popup menu command\n");
14939 flush_sequence();
14940 keybd_event(VK_MENU, 0, 0, 0);
14941 keybd_event('F', 0, 0, 0);
14942 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
14943 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
14944 keybd_event(VK_RIGHT, 0, 0, 0);
14945 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
14946 keybd_event(VK_RETURN, 0, 0, 0);
14947 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
14948 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14949 {
14950 TranslateMessage(&msg);
14951 DispatchMessageA(&msg);
14952 }
14953 ok_sequence(wm_popup_menu_2, "submenu of a popup menu command", FALSE);
14954
14955 trace("testing single menu item command\n");
14956 flush_sequence();
14957 keybd_event(VK_MENU, 0, 0, 0);
14958 keybd_event('Q', 0, 0, 0);
14959 keybd_event('Q', 0, KEYEVENTF_KEYUP, 0);
14960 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
14961 keybd_event(VK_ESCAPE, 0, 0, 0);
14962 keybd_event(VK_ESCAPE, 0, KEYEVENTF_KEYUP, 0);
14963 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14964 {
14965 TranslateMessage(&msg);
14966 DispatchMessageA(&msg);
14967 }
14968 ok_sequence(wm_single_menu_item, "single menu item command", FALSE);
14969
14970 set_menu_style(hmenu, 0);
14971 style = get_menu_style(hmenu);
14972 ok(style == 0, "expected 0, got %u\n", style);
14973
14974 hmenu_popup = GetSubMenu(hmenu, 0);
14975 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
14976 set_menu_style(hmenu_popup, MNS_NOTIFYBYPOS);
14977 style = get_menu_style(hmenu_popup);
14978 ok(style == MNS_NOTIFYBYPOS, "expected MNS_NOTIFYBYPOS, got %u\n", style);
14979
14980 hmenu_popup = GetSubMenu(hmenu_popup, 0);
14981 ok(hmenu_popup != 0, "GetSubMenu returned 0 for submenu 0\n");
14982 style = get_menu_style(hmenu_popup);
14983 ok(style == 0, "expected 0, got %u\n", style);
14984
14985 /* Alt+F, Right, Enter */
14986 trace("testing submenu of a popup menu command\n");
14987 flush_sequence();
14988 keybd_event(VK_MENU, 0, 0, 0);
14989 keybd_event('F', 0, 0, 0);
14990 keybd_event('F', 0, KEYEVENTF_KEYUP, 0);
14991 keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
14992 keybd_event(VK_RIGHT, 0, 0, 0);
14993 keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
14994 keybd_event(VK_RETURN, 0, 0, 0);
14995 keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
14996 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
14997 {
14998 TranslateMessage(&msg);
14999 DispatchMessageA(&msg);
15000 }
15001 ok_sequence(wm_popup_menu_3, "submenu of a popup menu command", FALSE);
15002
15003 done:
15004 DestroyWindow(hwnd);
15005 DestroyMenu(hmenu);
15006 }
15007
15008
15009 static void test_paintingloop(void)
15010 {
15011 HWND hwnd;
15012
15013 paint_loop_done = FALSE;
15014 hwnd = CreateWindowExA(0x0,"PaintLoopWindowClass",
15015 "PaintLoopWindowClass",WS_OVERLAPPEDWINDOW,
15016 100, 100, 100, 100, 0, 0, 0, NULL );
15017 ok(hwnd != 0, "PaintLoop window error %u\n", GetLastError());
15018 ShowWindow(hwnd,SW_NORMAL);
15019 SetFocus(hwnd);
15020
15021 while (!paint_loop_done)
15022 {
15023 MSG msg;
15024 if (PeekMessageA(&msg, 0, 0, 0, 1))
15025 {
15026 TranslateMessage(&msg);
15027 DispatchMessageA(&msg);
15028 }
15029 }
15030 DestroyWindow(hwnd);
15031 }
15032
15033 static const struct message NCRBUTTONDOWNSeq[] =
15034 {
15035 { EVENT_SYSTEM_CAPTURESTART, winevent_hook|wparam|lparam, 0, 0 },
15036 { EVENT_SYSTEM_CAPTUREEND, winevent_hook|wparam|lparam, 0, 0 },
15037 { WM_CAPTURECHANGED, sent },
15038 { WM_CONTEXTMENU, sent, /*hwnd*/0, -1 },
15039 { 0 }
15040 };
15041
15042 static const struct message NCXBUTTONUPSeq1[] =
15043 {
15044 { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_BACKWARD) },
15045 { 0 }
15046 };
15047
15048 static const struct message NCXBUTTONUPSeq2[] =
15049 {
15050 { WM_APPCOMMAND, sent|lparam, /*hwnd*/0, MAKELPARAM(0, FAPPCOMMAND_MOUSE | APPCOMMAND_BROWSER_FORWARD) },
15051 { 0 }
15052 };
15053
15054 struct rbuttonup_thread_data
15055 {
15056 HWND hwnd;
15057 HANDLE wndproc_finished;
15058 };
15059
15060 static DWORD CALLBACK post_rbuttonup_msg( void *arg )
15061 {
15062 struct rbuttonup_thread_data *data = arg;
15063 DWORD ret;
15064
15065 ret = WaitForSingleObject( data->wndproc_finished, 500 );
15066 todo_wine ok( ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", ret );
15067 if( ret == WAIT_OBJECT_0 ) return 0;
15068
15069 PostMessageA( data->hwnd, WM_RBUTTONUP, 0, 0 );
15070 return 0;
15071 }
15072
15073 static void test_defwinproc(void)
15074 {
15075 HWND hwnd;
15076 MSG msg;
15077 BOOL gotwmquit = FALSE;
15078 POINT pos;
15079 RECT rect;
15080 INT x, y;
15081 LRESULT res;
15082 struct rbuttonup_thread_data data;
15083 char buffA[64];
15084 HANDLE thread;
15085
15086 hwnd = CreateWindowExA(0, "TestWindowClass", "test_defwndproc",
15087 WS_VISIBLE | WS_CAPTION | WS_OVERLAPPEDWINDOW, 0,0,500,100,0,0,0, NULL);
15088 assert(hwnd);
15089 flush_events();
15090
15091 buffA[0] = 0;
15092 GetWindowTextA(hwnd, buffA, sizeof(buffA)/sizeof(*buffA));
15093 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15094
15095 /* Zero high word of the lParam */
15096 res = DefWindowProcA(hwnd, WM_SETTEXT, 0, 0x1234);
15097 ok(res == 0, "WM_SETTEXT was expected to fail, %ld\n", res);
15098
15099 GetWindowTextA(hwnd, buffA, sizeof(buffA)/sizeof(*buffA));
15100 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15101
15102 res = DefWindowProcW(hwnd, WM_SETTEXT, 0, 0x1234);
15103 ok(res == 0, "WM_SETTEXT was expected to fail, %ld\n", res);
15104
15105 GetWindowTextA(hwnd, buffA, sizeof(buffA)/sizeof(*buffA));
15106 ok(!strcmp(buffA, "test_defwndproc"), "unexpected window text, %s\n", buffA);
15107
15108 GetCursorPos(&pos);
15109 GetWindowRect(hwnd, &rect);
15110 x = (rect.left+rect.right) / 2;
15111 y = rect.top + GetSystemMetrics(SM_CYFRAME) + 1;
15112 SetCursorPos(x, y);
15113 flush_events();
15114 res = DefWindowProcA( hwnd, WM_NCHITTEST, 0, MAKELPARAM(x, y));
15115 ok(res == HTCAPTION, "WM_NCHITTEST returned %ld\n", res);
15116
15117 mouse_event( MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0 );
15118 mouse_event( MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 );
15119 flush_events();
15120
15121 flush_sequence();
15122 mouse_event( MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0 );
15123 /* workaround for missing support for clicking on window frame */
15124 data.hwnd = hwnd;
15125 data.wndproc_finished = CreateEventA( NULL, FALSE, FALSE, NULL );
15126 thread = CreateThread( NULL, 0, post_rbuttonup_msg, (void*)&data, 0, NULL );
15127
15128 DefWindowProcA( hwnd, WM_NCRBUTTONDOWN, HTCAPTION, MAKELPARAM(x, y));
15129 ok_sequence(NCRBUTTONDOWNSeq, "WM_NCRBUTTONDOWN on caption", FALSE);
15130
15131 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, 0, MAKELPARAM(x, y));
15132 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15133 ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP without button", FALSE);
15134
15135 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON1), MAKELPARAM(x, y));
15136 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15137 ok_sequence(NCXBUTTONUPSeq1, "WM_NCXBUTTONUP with XBUTTON1", FALSE);
15138
15139 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, XBUTTON2), MAKELPARAM(x, y));
15140 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15141 ok_sequence(NCXBUTTONUPSeq2, "WM_NCXBUTTONUP with XBUTTON2", FALSE);
15142
15143 res = DefWindowProcA(hwnd, WM_NCXBUTTONUP, MAKEWPARAM(0, 3), MAKELPARAM(x, y));
15144 ok(!res, "WM_NCXBUTTONUP returned %ld\n", res);
15145 ok_sequence(WmEmptySeq, "WM_NCXBUTTONUP with invalid button", FALSE);
15146
15147 SetEvent( data.wndproc_finished );
15148 WaitForSingleObject( thread, 1000 );
15149 CloseHandle( data.wndproc_finished );
15150 CloseHandle( thread );
15151
15152 SetCursorPos(pos.x, pos.y);
15153
15154 DefWindowProcA( hwnd, WM_ENDSESSION, 1, 0);
15155 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) {
15156 if( msg.message == WM_QUIT) gotwmquit = TRUE;
15157 DispatchMessageA( &msg );
15158 }
15159 ok(!gotwmquit, "Unexpected WM_QUIT message!\n");
15160 DestroyWindow( hwnd);
15161 }
15162
15163 #define clear_clipboard(hwnd) clear_clipboard_(__LINE__, (hwnd))
15164 static void clear_clipboard_(int line, HWND hWnd)
15165 {
15166 BOOL succ;
15167 succ = OpenClipboard(hWnd);
15168 ok_(__FILE__, line)(succ, "OpenClipboard failed, err=%u\n", GetLastError());
15169 succ = EmptyClipboard();
15170 ok_(__FILE__, line)(succ, "EmptyClipboard failed, err=%u\n", GetLastError());
15171 succ = CloseClipboard();
15172 ok_(__FILE__, line)(succ, "CloseClipboard failed, err=%u\n", GetLastError());
15173 }
15174
15175 #define expect_HWND(expected, got) expect_HWND_(__LINE__, (expected), (got))
15176 static void expect_HWND_(int line, HWND expected, HWND got)
15177 {
15178 ok_(__FILE__, line)(got==expected, "Expected %p, got %p\n", expected, got);
15179 }
15180
15181 static WNDPROC pOldViewerProc;
15182
15183 static LRESULT CALLBACK recursive_viewer_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
15184 {
15185 static BOOL recursion_guard;
15186
15187 if (message == WM_DRAWCLIPBOARD && !recursion_guard)
15188 {
15189 recursion_guard = TRUE;
15190 clear_clipboard(hWnd);
15191 recursion_guard = FALSE;
15192 }
15193 return CallWindowProcA(pOldViewerProc, hWnd, message, wParam, lParam);
15194 }
15195
15196 static void test_clipboard_viewers(void)
15197 {
15198 static struct message wm_change_cb_chain[] =
15199 {
15200 { WM_CHANGECBCHAIN, sent|wparam|lparam, 0, 0 },
15201 { 0 }
15202 };
15203 static const struct message wm_clipboard_destroyed[] =
15204 {
15205 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
15206 { 0 }
15207 };
15208 static struct message wm_clipboard_changed[] =
15209 {
15210 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
15211 { 0 }
15212 };
15213 static struct message wm_clipboard_changed_and_owned[] =
15214 {
15215 { WM_DESTROYCLIPBOARD, sent|wparam|lparam, 0, 0 },
15216 { WM_DRAWCLIPBOARD, sent|wparam|lparam, 0, 0 },
15217 { 0 }
15218 };
15219
15220 HINSTANCE hInst = GetModuleHandleA(NULL);
15221 HWND hWnd1, hWnd2, hWnd3;
15222 HWND hOrigViewer;
15223 HWND hRet;
15224
15225 hWnd1 = CreateWindowExA(0, "TestWindowClass", "Clipboard viewer test wnd 1",
15226 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
15227 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
15228 GetDesktopWindow(), NULL, hInst, NULL);
15229 hWnd2 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 2",
15230 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
15231 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
15232 GetDesktopWindow(), NULL, hInst, NULL);
15233 hWnd3 = CreateWindowExA(0, "SimpleWindowClass", "Clipboard viewer test wnd 3",
15234 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
15235 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
15236 GetDesktopWindow(), NULL, hInst, NULL);
15237 trace("clipbd viewers: hWnd1=%p, hWnd2=%p, hWnd3=%p\n", hWnd1, hWnd2, hWnd3);
15238 assert(hWnd1 && hWnd2 && hWnd3);
15239
15240 CountClipboardFormats(); /* Ensure that we do not have an X11 update to the clipboard */
15241 flush_sequence();
15242
15243 /* Test getting the clipboard viewer and setting the viewer to NULL. */
15244 hOrigViewer = GetClipboardViewer();
15245 hRet = SetClipboardViewer(NULL);
15246 ok_sequence(WmEmptySeq, "set viewer to NULL", FALSE);
15247 expect_HWND(hOrigViewer, hRet);
15248 expect_HWND(NULL, GetClipboardViewer());
15249
15250 /* Test registering hWnd1 as a viewer. */
15251 hRet = SetClipboardViewer(hWnd1);
15252 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
15253 ok_sequence(wm_clipboard_changed, "set viewer NULL->1", FALSE);
15254 expect_HWND(NULL, hRet);
15255 expect_HWND(hWnd1, GetClipboardViewer());
15256
15257 /* Test that changing the clipboard actually refreshes the registered viewer. */
15258 clear_clipboard(hWnd1);
15259 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
15260 ok_sequence(wm_clipboard_changed, "clear clipbd (viewer=owner=1)", FALSE);
15261
15262 /* Again, but with different owner. */
15263 clear_clipboard(hWnd2);
15264 wm_clipboard_changed_and_owned[1].wParam = (WPARAM) GetClipboardOwner();
15265 ok_sequence(wm_clipboard_changed_and_owned, "clear clipbd (viewer=1, owner=2)", FALSE);
15266
15267 /* Test re-registering same window. */
15268 hRet = SetClipboardViewer(hWnd1);
15269 wm_clipboard_changed[0].wParam = (WPARAM) GetClipboardOwner();
15270 ok_sequence(wm_clipboard_changed, "set viewer 1->1", FALSE);
15271 expect_HWND(hWnd1, hRet);
15272 expect_HWND(hWnd1, GetClipboardViewer());
15273
15274 /* Test ChangeClipboardChain. */
15275 ChangeClipboardChain(hWnd2, hWnd3);
15276 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
15277 wm_change_cb_chain[0].lParam = (LPARAM) hWnd3;
15278 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=3)", FALSE);
15279 expect_HWND(hWnd1, GetClipboardViewer());
15280
15281 ChangeClipboardChain(hWnd2, NULL);
15282 wm_change_cb_chain[0].wParam = (WPARAM) hWnd2;
15283 wm_change_cb_chain[0].lParam = 0;
15284 ok_sequence(wm_change_cb_chain, "change chain (viewer=1, remove=2, next=NULL)", FALSE);
15285 expect_HWND(hWnd1, GetClipboardViewer());
15286
15287 ChangeClipboardChain(NULL, hWnd2);
15288 ok_sequence(WmEmptySeq, "change chain (viewer=1, remove=NULL, next=2)", FALSE);
15289 expect_HWND(hWnd1, GetClipboardViewer());
15290
15291 /* Actually change clipboard viewer with ChangeClipboardChain. */
15292 ChangeClipboardChain(hWnd1, hWnd2);
15293 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=2)", FALSE);
15294 expect_HWND(hWnd2, GetClipboardViewer());
15295
15296 /* Test that no refresh messages are sent when viewer has unregistered. */
15297 clear_clipboard(hWnd2);
15298 ok_sequence(WmEmptySeq, "clear clipd (viewer=2, owner=1)", FALSE);
15299
15300 /* Register hWnd1 again. */
15301 ChangeClipboardChain(hWnd2, hWnd1);
15302 ok_sequence(WmEmptySeq, "change chain (viewer=remove=2, next=1)", FALSE);
15303 expect_HWND(hWnd1, GetClipboardViewer());
15304
15305 /* Subclass hWnd1 so that when it receives a WM_DRAWCLIPBOARD message, it
15306 * changes the clipboard. When this happens, the system shouldn't send
15307 * another WM_DRAWCLIPBOARD (as this could cause an infinite loop).
15308 */
15309 pOldViewerProc = (WNDPROC) SetWindowLongPtrA(hWnd1, GWLP_WNDPROC, (LONG_PTR) recursive_viewer_proc);
15310 clear_clipboard(hWnd2);
15311 /* The clipboard owner is changed in recursive_viewer_proc: */
15312 wm_clipboard_changed[0].wParam = (WPARAM) hWnd2;
15313 ok_sequence(wm_clipboard_changed, "recursive clear clipbd (viewer=1, owner=2)", TRUE);
15314
15315 /* Test unregistering. */
15316 ChangeClipboardChain(hWnd1, NULL);
15317 ok_sequence(WmEmptySeq, "change chain (viewer=remove=1, next=NULL)", FALSE);
15318 expect_HWND(NULL, GetClipboardViewer());
15319
15320 clear_clipboard(hWnd1);
15321 ok_sequence(wm_clipboard_destroyed, "clear clipbd (no viewer, owner=1)", FALSE);
15322
15323 DestroyWindow(hWnd1);
15324 DestroyWindow(hWnd2);
15325 DestroyWindow(hWnd3);
15326 SetClipboardViewer(hOrigViewer);
15327 }
15328
15329 static void test_PostMessage(void)
15330 {
15331 static const struct
15332 {
15333 HWND hwnd;
15334 BOOL ret;
15335 } data[] =
15336 {
15337 { HWND_TOP /* 0 */, TRUE },
15338 { HWND_BROADCAST, TRUE },
15339 { HWND_BOTTOM, TRUE },
15340 { HWND_TOPMOST, TRUE },
15341 { HWND_NOTOPMOST, FALSE },
15342 { HWND_MESSAGE, FALSE },
15343 { (HWND)0xdeadbeef, FALSE }
15344 };
15345 int i;
15346 HWND hwnd;
15347 BOOL ret;
15348 MSG msg;
15349 static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
15350
15351 SetLastError(0xdeadbeef);
15352 hwnd = CreateWindowExW(0, staticW, NULL, WS_POPUP, 0,0,0,0,0,0,0, NULL);
15353 if (!hwnd && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
15354 {
15355 win_skip("Skipping some PostMessage tests on Win9x/WinMe\n");
15356 return;
15357 }
15358 assert(hwnd);
15359
15360 flush_events();
15361
15362 PostMessageA(hwnd, WM_USER+1, 0x1234, 0x5678);
15363 PostMessageA(0, WM_USER+2, 0x5678, 0x1234);
15364
15365 for (i = 0; i < sizeof(data)/sizeof(data[0]); i++)
15366 {
15367 memset(&msg, 0xab, sizeof(msg));
15368 ret = PeekMessageA(&msg, data[i].hwnd, 0, 0, PM_NOREMOVE);
15369 ok(ret == data[i].ret, "%d: hwnd %p expected %d, got %d\n", i, data[i].hwnd, data[i].ret, ret);
15370 if (data[i].ret)
15371 {
15372 if (data[i].hwnd)
15373 ok(ret && msg.hwnd == 0 && msg.message == WM_USER+2 &&
15374 msg.wParam == 0x5678 && msg.lParam == 0x1234,
15375 "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/0/WM_USER+2/0x5678/0x1234\n",
15376 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam);
15377 else
15378 ok(ret && msg.hwnd == hwnd && msg.message == WM_USER+1 &&
15379 msg.wParam == 0x1234 && msg.lParam == 0x5678,
15380 "%d: got ret %d hwnd %p msg %04x wParam %08lx lParam %08lx instead of TRUE/%p/WM_USER+1/0x1234/0x5678\n",
15381 i, ret, msg.hwnd, msg.message, msg.wParam, msg.lParam, msg.hwnd);
15382 }
15383 }
15384
15385 DestroyWindow(hwnd);
15386 flush_events();
15387 }
15388
15389 static LPARAM g_broadcast_lparam;
15390 static LRESULT WINAPI broadcast_test_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
15391 {
15392 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
15393
15394 if (wParam == 0xbaadbeef)
15395 g_broadcast_lparam = wParam;
15396 else
15397 g_broadcast_lparam = 0;
15398
15399 return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
15400 }
15401
15402 static void test_broadcast(void)
15403 {
15404 static const UINT messages[] =
15405 {
15406 WM_USER-1,
15407 WM_USER,
15408 WM_USER+1,
15409 0xc000-1,
15410 0xc000, /* lowest possible atom returned by RegisterWindowMessage */
15411 0xffff,
15412 };
15413 WNDPROC oldproc;
15414 unsigned int i;
15415 HWND hwnd;
15416
15417 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, NULL);
15418 ok(hwnd != NULL, "got %p\n", hwnd);
15419
15420 oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)broadcast_test_proc);
15421 SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc);
15422
15423 for (i = 0; i < sizeof(messages)/sizeof(messages[0]); i++)
15424 {
15425 BOOL ret;
15426 MSG msg;
15427
15428 flush_events();
15429 while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
15430 ;
15431
15432 /* post, broadcast */
15433 ret = PostMessageA(HWND_BROADCAST, messages[i], 0, 0);
15434 ok(ret, "%d: got %d, error %d\n", i, ret, GetLastError());
15435
15436 memset(&msg, 0xab, sizeof(msg));
15437 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
15438 if (messages[i] < WM_USER || messages[i] >= 0xc000)
15439 {
15440 ok(ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
15441 ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
15442 }
15443 else
15444 {
15445 ok(!ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
15446 }
15447
15448 /* post, topmost */
15449 ret = PostMessageA(HWND_TOPMOST, messages[i], 0, 0);
15450 ok(ret, "%d: got %d, error %d\n", i, ret, GetLastError());
15451
15452 memset(&msg, 0xab, sizeof(msg));
15453 ret = PeekMessageA(&msg, 0, 0, 0, PM_REMOVE);
15454 if (messages[i] < WM_USER || messages[i] >= 0xc000)
15455 {
15456 ok(ret, "%d: message %04x, got %d, error %d\n", i, messages[i], ret, GetLastError());
15457 ok(msg.hwnd == hwnd, "%d: got %p\n", i, msg.hwnd);
15458 }
15459 else
15460 {
15461 ok(!ret, "%d: got %d, error %d\n", i, ret, GetLastError());
15462 }
15463
15464 /* send, broadcast */
15465 g_broadcast_lparam = 0xdead;
15466 ret = SendMessageTimeoutA(HWND_BROADCAST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
15467 if (!ret && GetLastError() == ERROR_TIMEOUT)
15468 win_skip("broadcasting test %d, timeout\n", i);
15469 else
15470 {
15471 if (messages[i] < WM_USER || messages[i] >= 0xc000)
15472 {
15473 ok(g_broadcast_lparam == 0xbaadbeef, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
15474 g_broadcast_lparam, GetLastError());
15475 }
15476 else
15477 {
15478 ok(g_broadcast_lparam == 0xdead, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
15479 g_broadcast_lparam, GetLastError());
15480 }
15481 }
15482
15483 /* send, topmost */
15484 g_broadcast_lparam = 0xdead;
15485 ret = SendMessageTimeoutA(HWND_TOPMOST, messages[i], 0xbaadbeef, 0, SMTO_NORMAL, 2000, NULL);
15486 if (!ret && GetLastError() == ERROR_TIMEOUT)
15487 win_skip("broadcasting test %d, timeout\n", i);
15488 else
15489 {
15490 if (messages[i] < WM_USER || messages[i] >= 0xc000)
15491 {
15492 ok(g_broadcast_lparam == 0xbaadbeef, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
15493 g_broadcast_lparam, GetLastError());
15494 }
15495 else
15496 {
15497 ok(g_broadcast_lparam == 0xdead, "%d: message %04x, got %#lx, error %d\n", i, messages[i],
15498 g_broadcast_lparam, GetLastError());
15499 }
15500 }
15501 }
15502
15503 DestroyWindow(hwnd);
15504 }
15505
15506 static const struct
15507 {
15508 DWORD exp, broken;
15509 BOOL todo;
15510 } wait_idle_expect[] =
15511 {
15512 /* 0 */ { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
15513 { WAIT_TIMEOUT, 0, FALSE },
15514 { WAIT_TIMEOUT, 0, FALSE },
15515 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
15516 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
15517 /* 5 */ { WAIT_TIMEOUT, 0, FALSE },
15518 { WAIT_TIMEOUT, 0, FALSE },
15519 { WAIT_TIMEOUT, WAIT_TIMEOUT, FALSE },
15520 { 0, 0, FALSE },
15521 { 0, 0, FALSE },
15522 /* 10 */ { 0, 0, FALSE },
15523 { 0, 0, FALSE },
15524 { 0, WAIT_TIMEOUT, FALSE },
15525 { 0, 0, FALSE },
15526 { 0, 0, FALSE },
15527 /* 15 */ { 0, 0, FALSE },
15528 { WAIT_TIMEOUT, 0, FALSE },
15529 { WAIT_TIMEOUT, 0, FALSE },
15530 { WAIT_TIMEOUT, 0, FALSE },
15531 { WAIT_TIMEOUT, 0, FALSE },
15532 /* 20 */ { WAIT_TIMEOUT, 0, FALSE },
15533 };
15534
15535 static DWORD CALLBACK do_wait_idle_child_thread( void *arg )
15536 {
15537 MSG msg;
15538
15539 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15540 Sleep( 200 );
15541 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
15542 return 0;
15543 }
15544
15545 static void do_wait_idle_child( int arg )
15546 {
15547 WNDCLASSA cls;
15548 MSG msg;
15549 HWND hwnd = 0;
15550 HANDLE thread;
15551 DWORD id;
15552 HANDLE start_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_start" );
15553 HANDLE end_event = OpenEventA( EVENT_ALL_ACCESS, FALSE, "test_WaitForInputIdle_end" );
15554
15555 memset( &cls, 0, sizeof(cls) );
15556 cls.lpfnWndProc = DefWindowProcA;
15557 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
15558 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
15559 cls.lpszClassName = "TestClass";
15560 RegisterClassA( &cls );
15561
15562 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ); /* create the msg queue */
15563
15564 ok( start_event != 0, "failed to create start event, error %u\n", GetLastError() );
15565 ok( end_event != 0, "failed to create end event, error %u\n", GetLastError() );
15566
15567 switch (arg)
15568 {
15569 case 0:
15570 SetEvent( start_event );
15571 break;
15572 case 1:
15573 SetEvent( start_event );
15574 Sleep( 200 );
15575 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
15576 break;
15577 case 2:
15578 SetEvent( start_event );
15579 Sleep( 200 );
15580 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15581 PostThreadMessageA( GetCurrentThreadId(), WM_COMMAND, 0x1234, 0xabcd );
15582 PeekMessageA( &msg, 0, 0, 0, PM_REMOVE );
15583 break;
15584 case 3:
15585 SetEvent( start_event );
15586 Sleep( 200 );
15587 SendMessageA( HWND_BROADCAST, WM_WININICHANGE, 0, 0 );
15588 break;
15589 case 4:
15590 SetEvent( start_event );
15591 Sleep( 200 );
15592 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15593 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
15594 break;
15595 case 5:
15596 SetEvent( start_event );
15597 Sleep( 200 );
15598 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15599 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
15600 break;
15601 case 6:
15602 SetEvent( start_event );
15603 Sleep( 200 );
15604 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15605 while (PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE ))
15606 {
15607 GetMessageA( &msg, 0, 0, 0 );
15608 DispatchMessageA( &msg );
15609 }
15610 break;
15611 case 7:
15612 SetEvent( start_event );
15613 Sleep( 200 );
15614 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15615 SetTimer( hwnd, 3, 1, NULL );
15616 Sleep( 200 );
15617 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD )) DispatchMessageA( &msg );
15618 break;
15619 case 8:
15620 SetEvent( start_event );
15621 Sleep( 200 );
15622 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15623 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
15624 break;
15625 case 9:
15626 SetEvent( start_event );
15627 Sleep( 200 );
15628 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15629 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
15630 for (;;) GetMessageA( &msg, 0, 0, 0 );
15631 break;
15632 case 10:
15633 SetEvent( start_event );
15634 Sleep( 200 );
15635 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP|WS_VISIBLE, 0, 0, 10, 10, 0, 0, 0, NULL);
15636 SetTimer( hwnd, 3, 1, NULL );
15637 Sleep( 200 );
15638 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
15639 break;
15640 case 11:
15641 SetEvent( start_event );
15642 Sleep( 200 );
15643 return; /* exiting the process makes WaitForInputIdle return success too */
15644 case 12:
15645 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15646 Sleep( 200 );
15647 MsgWaitForMultipleObjects( 0, NULL, FALSE, 100, QS_ALLINPUT );
15648 SetEvent( start_event );
15649 break;
15650 case 13:
15651 SetEvent( start_event );
15652 PeekMessageA( &msg, 0, 0, 0, PM_NOREMOVE );
15653 Sleep( 200 );
15654 thread = CreateThread( NULL, 0, do_wait_idle_child_thread, NULL, 0, &id );
15655 WaitForSingleObject( thread, 10000 );
15656 CloseHandle( thread );
15657 break;
15658 case 14:
15659 SetEvent( start_event );
15660 Sleep( 200 );
15661 PeekMessageA( &msg, HWND_TOPMOST, 0, 0, PM_NOREMOVE );
15662 break;
15663 case 15:
15664 SetEvent( start_event );
15665 Sleep( 200 );
15666 PeekMessageA( &msg, HWND_BROADCAST, 0, 0, PM_NOREMOVE );
15667 break;
15668 case 16:
15669 SetEvent( start_event );
15670 Sleep( 200 );
15671 PeekMessageA( &msg, HWND_BOTTOM, 0, 0, PM_NOREMOVE );
15672 break;
15673 case 17:
15674 SetEvent( start_event );
15675 Sleep( 200 );
15676 PeekMessageA( &msg, (HWND)0xdeadbeef, 0, 0, PM_NOREMOVE );
15677 break;
15678 case 18:
15679 SetEvent( start_event );
15680 Sleep( 200 );
15681 PeekMessageA( &msg, HWND_NOTOPMOST, 0, 0, PM_NOREMOVE );
15682 break;
15683 case 19:
15684 SetEvent( start_event );
15685 Sleep( 200 );
15686 PeekMessageA( &msg, HWND_MESSAGE, 0, 0, PM_NOREMOVE );
15687 break;
15688 case 20:
15689 SetEvent( start_event );
15690 Sleep( 200 );
15691 PeekMessageA( &msg, GetDesktopWindow(), 0, 0, PM_NOREMOVE );
15692 break;
15693 }
15694 WaitForSingleObject( end_event, 2000 );
15695 CloseHandle( start_event );
15696 CloseHandle( end_event );
15697 if (hwnd) DestroyWindow( hwnd );
15698 }
15699
15700 static LRESULT CALLBACK wait_idle_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
15701 {
15702 if (msg == WM_WININICHANGE) Sleep( 200 ); /* make sure the child waits */
15703 return DefWindowProcA( hwnd, msg, wp, lp );
15704 }
15705
15706 static DWORD CALLBACK wait_idle_thread( void *arg )
15707 {
15708 WNDCLASSA cls;
15709 MSG msg;
15710 HWND hwnd;
15711
15712 memset( &cls, 0, sizeof(cls) );
15713 cls.lpfnWndProc = wait_idle_proc;
15714 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
15715 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
15716 cls.lpszClassName = "TestClass";
15717 RegisterClassA( &cls );
15718
15719 hwnd = CreateWindowExA(0, "TestClass", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL);
15720 while (GetMessageA( &msg, 0, 0, 0 )) DispatchMessageA( &msg );
15721 DestroyWindow(hwnd);
15722 return 0;
15723 }
15724
15725 static void test_WaitForInputIdle( char *argv0 )
15726 {
15727 char path[MAX_PATH];
15728 PROCESS_INFORMATION pi;
15729 STARTUPINFOA startup;
15730 BOOL ret;
15731 HANDLE start_event, end_event, thread;
15732 unsigned int i;
15733 DWORD id;
15734 const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)GetModuleHandleA(0);
15735 const IMAGE_NT_HEADERS *nt = (const IMAGE_NT_HEADERS *)((const char *)dos + dos->e_lfanew);
15736 BOOL console_app = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI);
15737
15738 if (console_app) /* build the test with -mwindows for better coverage */
15739 trace( "not built as a GUI app, WaitForInputIdle may not be fully tested\n" );
15740
15741 start_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_start");
15742 end_event = CreateEventA(NULL, 0, 0, "test_WaitForInputIdle_end");
15743 ok(start_event != 0, "failed to create start event, error %u\n", GetLastError());
15744 ok(end_event != 0, "failed to create end event, error %u\n", GetLastError());
15745
15746 memset( &startup, 0, sizeof(startup) );
15747 startup.cb = sizeof(startup);
15748 startup.dwFlags = STARTF_USESHOWWINDOW;
15749 startup.wShowWindow = SW_SHOWNORMAL;
15750
15751 thread = CreateThread( NULL, 0, wait_idle_thread, NULL, 0, &id );
15752
15753 for (i = 0; i < sizeof(wait_idle_expect)/sizeof(wait_idle_expect[0]); i++)
15754 {
15755 ResetEvent( start_event );
15756 ResetEvent( end_event );
15757 #ifndef __REACTOS__
15758 sprintf( path, "%s msg %u", argv0, i );
15759 #else
15760 sprintf( path, "%s msg_queue %u", argv0, i );
15761 #endif
15762 ret = CreateProcessA( NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &pi );
15763 ok( ret, "CreateProcess '%s' failed err %u.\n", path, GetLastError() );
15764 if (ret)
15765 {
15766 ret = WaitForSingleObject( start_event, 5000 );
15767 ok( ret == WAIT_OBJECT_0, "%u: WaitForSingleObject failed\n", i );
15768 if (ret == WAIT_OBJECT_0)
15769 {
15770 ret = WaitForInputIdle( pi.hProcess, 1000 );
15771 if (ret == WAIT_FAILED)
15772 ok( console_app ||
15773 ret == wait_idle_expect[i].exp ||
15774 broken(ret == wait_idle_expect[i].broken),
15775 "%u: WaitForInputIdle error %08x expected %08x\n",
15776 i, ret, wait_idle_expect[i].exp );
15777 else todo_wine_if (wait_idle_expect[i].todo)
15778 ok( ret == wait_idle_expect[i].exp || broken(ret == wait_idle_expect[i].broken),
15779 "%u: WaitForInputIdle error %08x expected %08x\n",
15780 i, ret, wait_idle_expect[i].exp );
15781 SetEvent( end_event );
15782 WaitForSingleObject( pi.hProcess, 1000 ); /* give it a chance to exit on its own */
15783 }
15784 TerminateProcess( pi.hProcess, 0 ); /* just in case */
15785 winetest_wait_child_process( pi.hProcess );
15786 ret = WaitForInputIdle( pi.hProcess, 100 );
15787 ok( ret == WAIT_FAILED, "%u: WaitForInputIdle after exit error %08x\n", i, ret );
15788 CloseHandle( pi.hProcess );
15789 CloseHandle( pi.hThread );
15790 }
15791 }
15792 CloseHandle( start_event );
15793 PostThreadMessageA( id, WM_QUIT, 0, 0 );
15794 WaitForSingleObject( thread, 10000 );
15795 CloseHandle( thread );
15796 }
15797
15798 static const struct message WmSetParentSeq_1[] = {
15799 { WM_SHOWWINDOW, sent|wparam, 0 },
15800 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15801 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
15802 { WM_CHILDACTIVATE, sent },
15803 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOREDRAW|SWP_NOCLIENTSIZE },
15804 { WM_MOVE, sent|defwinproc|wparam, 0 },
15805 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15806 { WM_SHOWWINDOW, sent|wparam, 1 },
15807 { 0 }
15808 };
15809
15810 static const struct message WmSetParentSeq_2[] = {
15811 { WM_SHOWWINDOW, sent|wparam, 0 },
15812 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE },
15813 { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 },
15814 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15815 { HCBT_SETFOCUS, hook|optional },
15816 { WM_NCACTIVATE, sent|wparam|optional, 0 },
15817 { WM_ACTIVATE, sent|wparam|optional, 0 },
15818 { WM_ACTIVATEAPP, sent|wparam|optional, 0 },
15819 { WM_KILLFOCUS, sent|wparam, 0 },
15820 { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15821 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE },
15822 { HCBT_ACTIVATE, hook|optional },
15823 { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam, 0, 0 },
15824 { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE },
15825 { WM_NCACTIVATE, sent|wparam|optional, 1 },
15826 { WM_ACTIVATE, sent|wparam|optional, 1 },
15827 { HCBT_SETFOCUS, hook|optional },
15828 { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 },
15829 { WM_SETFOCUS, sent|optional|defwinproc },
15830 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOCLIENTSIZE },
15831 { WM_MOVE, sent|defwinproc|wparam, 0 },
15832 { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam, 0, 0 },
15833 { WM_SHOWWINDOW, sent|wparam, 1 },
15834 { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE },
15835 { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 },
15836 { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
15837 { 0 }
15838 };
15839
15840
15841 static void test_SetParent(void)
15842 {
15843 HWND parent1, parent2, child, popup;
15844 RECT rc, rc_old;
15845
15846 parent1 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
15847 100, 100, 200, 200, 0, 0, 0, NULL);
15848 ok(parent1 != 0, "Failed to create parent1 window\n");
15849
15850 parent2 = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
15851 400, 100, 200, 200, 0, 0, 0, NULL);
15852 ok(parent2 != 0, "Failed to create parent2 window\n");
15853
15854 /* WS_CHILD window */
15855 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD | WS_VISIBLE,
15856 10, 10, 150, 150, parent1, 0, 0, NULL);
15857 ok(child != 0, "Failed to create child window\n");
15858
15859 GetWindowRect(parent1, &rc);
15860 trace("parent1 %s\n", wine_dbgstr_rect(&rc));
15861 GetWindowRect(child, &rc_old);
15862 MapWindowPoints(0, parent1, (POINT *)&rc_old, 2);
15863 trace("child %s\n", wine_dbgstr_rect(&rc_old));
15864
15865 flush_sequence();
15866
15867 SetParent(child, parent2);
15868 flush_events();
15869 ok_sequence(WmSetParentSeq_1, "SetParent() visible WS_CHILD", TRUE);
15870
15871 ok(GetWindowLongA(child, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
15872 ok(!IsWindowVisible(child), "IsWindowVisible() should return FALSE\n");
15873
15874 GetWindowRect(parent2, &rc);
15875 trace("parent2 %s\n", wine_dbgstr_rect(&rc));
15876 GetWindowRect(child, &rc);
15877 MapWindowPoints(0, parent2, (POINT *)&rc, 2);
15878 trace("child %s\n", wine_dbgstr_rect(&rc));
15879
15880 ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
15881 wine_dbgstr_rect(&rc));
15882
15883 /* WS_POPUP window */
15884 popup = CreateWindowExA(0, "TestWindowClass", NULL, WS_POPUP | WS_VISIBLE,
15885 20, 20, 100, 100, 0, 0, 0, NULL);
15886 ok(popup != 0, "Failed to create popup window\n");
15887
15888 GetWindowRect(popup, &rc_old);
15889 trace("popup %s\n", wine_dbgstr_rect(&rc_old));
15890
15891 flush_sequence();
15892
15893 SetParent(popup, child);
15894 flush_events();
15895 ok_sequence(WmSetParentSeq_2, "SetParent() visible WS_POPUP", TRUE);
15896
15897 ok(GetWindowLongA(popup, GWL_STYLE) & WS_VISIBLE, "WS_VISIBLE should be set\n");
15898 ok(!IsWindowVisible(popup), "IsWindowVisible() should return FALSE\n");
15899
15900 GetWindowRect(child, &rc);
15901 trace("parent2 %s\n", wine_dbgstr_rect(&rc));
15902 GetWindowRect(popup, &rc);
15903 MapWindowPoints(0, child, (POINT *)&rc, 2);
15904 trace("popup %s\n", wine_dbgstr_rect(&rc));
15905
15906 ok(EqualRect(&rc_old, &rc), "rects do not match %s / %s\n", wine_dbgstr_rect(&rc_old),
15907 wine_dbgstr_rect(&rc));
15908
15909 DestroyWindow(popup);
15910 DestroyWindow(child);
15911 DestroyWindow(parent1);
15912 DestroyWindow(parent2);
15913
15914 flush_sequence();
15915 }
15916
15917 static const struct message WmKeyReleaseOnly[] = {
15918 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x80000001 },
15919 { WM_KEYUP, sent|wparam|lparam, 0x41, 0x80000001 },
15920 { 0 }
15921 };
15922 static const struct message WmKeyPressNormal[] = {
15923 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x1 },
15924 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x1 },
15925 { 0 }
15926 };
15927 static const struct message WmKeyPressRepeat[] = {
15928 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0x40000001 },
15929 { WM_KEYDOWN, sent|wparam|lparam, 0x41, 0x40000001 },
15930 { 0 }
15931 };
15932 static const struct message WmKeyReleaseNormal[] = {
15933 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, 0x41, 0xc0000001 },
15934 { WM_KEYUP, sent|wparam|lparam, 0x41, 0xc0000001 },
15935 { 0 }
15936 };
15937
15938 static void test_keyflags(void)
15939 {
15940 HWND test_window;
15941 SHORT key_state;
15942 BYTE keyboard_state[256];
15943 MSG msg;
15944
15945 test_window = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
15946 100, 100, 200, 200, 0, 0, 0, NULL);
15947
15948 flush_events();
15949 flush_sequence();
15950
15951 /* keyup without a keydown */
15952 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
15953 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
15954 DispatchMessageA(&msg);
15955 ok_sequence(WmKeyReleaseOnly, "key release only", TRUE);
15956
15957 key_state = GetAsyncKeyState(0x41);
15958 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
15959
15960 key_state = GetKeyState(0x41);
15961 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
15962
15963 /* keydown */
15964 keybd_event(0x41, 0, 0, 0);
15965 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
15966 DispatchMessageA(&msg);
15967 ok_sequence(WmKeyPressNormal, "key press only", FALSE);
15968
15969 key_state = GetAsyncKeyState(0x41);
15970 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15971
15972 key_state = GetKeyState(0x41);
15973 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15974
15975 /* keydown repeat */
15976 keybd_event(0x41, 0, 0, 0);
15977 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
15978 DispatchMessageA(&msg);
15979 ok_sequence(WmKeyPressRepeat, "key press repeat", FALSE);
15980
15981 key_state = GetAsyncKeyState(0x41);
15982 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15983
15984 key_state = GetKeyState(0x41);
15985 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
15986
15987 /* keyup */
15988 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
15989 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
15990 DispatchMessageA(&msg);
15991 ok_sequence(WmKeyReleaseNormal, "key release repeat", FALSE);
15992
15993 key_state = GetAsyncKeyState(0x41);
15994 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
15995
15996 key_state = GetKeyState(0x41);
15997 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
15998
15999 /* set the key state in this thread */
16000 GetKeyboardState(keyboard_state);
16001 keyboard_state[0x41] = 0x80;
16002 SetKeyboardState(keyboard_state);
16003
16004 key_state = GetAsyncKeyState(0x41);
16005 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16006
16007 /* keydown */
16008 keybd_event(0x41, 0, 0, 0);
16009 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16010 DispatchMessageA(&msg);
16011 ok_sequence(WmKeyPressRepeat, "key press after setkeyboardstate", TRUE);
16012
16013 key_state = GetAsyncKeyState(0x41);
16014 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16015
16016 key_state = GetKeyState(0x41);
16017 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16018
16019 /* clear the key state in this thread */
16020 GetKeyboardState(keyboard_state);
16021 keyboard_state[0x41] = 0;
16022 SetKeyboardState(keyboard_state);
16023
16024 key_state = GetAsyncKeyState(0x41);
16025 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16026
16027 /* keyup */
16028 keybd_event(0x41, 0, KEYEVENTF_KEYUP, 0);
16029 while (PeekMessageA(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
16030 DispatchMessageA(&msg);
16031 ok_sequence(WmKeyReleaseOnly, "key release after setkeyboardstate", TRUE);
16032
16033 key_state = GetAsyncKeyState(0x41);
16034 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16035
16036 key_state = GetKeyState(0x41);
16037 ok((key_state & 0x8000) == 0, "unexpected key state %x\n", key_state);
16038
16039 DestroyWindow(test_window);
16040 flush_sequence();
16041 }
16042
16043 static const struct message WmHotkeyPressLWIN[] = {
16044 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16045 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16046 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16047 { 0 }
16048 };
16049 static const struct message WmHotkeyPress[] = {
16050 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16051 { WM_HOTKEY, sent|wparam, 5 },
16052 { 0 }
16053 };
16054 static const struct message WmHotkeyRelease[] = {
16055 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16056 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 0x80000001 },
16057 { WM_KEYUP, sent|lparam, 0, 0x80000001 },
16058 { 0 }
16059 };
16060 static const struct message WmHotkeyReleaseLWIN[] = {
16061 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16062 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16063 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16064 { 0 }
16065 };
16066 static const struct message WmHotkeyCombined[] = {
16067 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16068 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16069 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16070 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16071 { WM_APP, sent, 0, 0 },
16072 { WM_HOTKEY, sent|wparam, 5 },
16073 { WM_APP+1, sent, 0, 0 },
16074 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16075 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16076 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
16077 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
16078 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16079 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16080 { 0 }
16081 };
16082 static const struct message WmHotkeyPrevious[] = {
16083 { WM_KEYDOWN, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED },
16084 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16085 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16086 { WM_KEYUP, kbd_hook|wparam|lparam, VK_LWIN, LLKHF_INJECTED|LLKHF_UP },
16087 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 1 },
16088 { WM_KEYDOWN, sent|wparam|lparam, VK_LWIN, 1 },
16089 { HCBT_KEYSKIPPED, hook|lparam|optional, 0, 1 },
16090 { WM_KEYDOWN, sent|lparam, 0, 1 },
16091 { HCBT_KEYSKIPPED, hook|optional|lparam, 0, 0xc0000001 },
16092 { WM_KEYUP, sent|lparam, 0, 0xc0000001 },
16093 { HCBT_KEYSKIPPED, hook|wparam|lparam|optional, VK_LWIN, 0xc0000001 },
16094 { WM_KEYUP, sent|wparam|lparam, VK_LWIN, 0xc0000001 },
16095 { 0 }
16096 };
16097 static const struct message WmHotkeyNew[] = {
16098 { WM_KEYDOWN, kbd_hook|lparam, 0, LLKHF_INJECTED },
16099 { WM_KEYUP, kbd_hook|lparam, 0, LLKHF_INJECTED|LLKHF_UP },
16100 { WM_HOTKEY, sent|wparam, 5 },
16101 { HCBT_KEYSKIPPED, hook|optional, 0, 0x80000001 },
16102 { WM_KEYUP, sent, 0, 0x80000001 }, /* lparam not checked so the sequence isn't a todo */
16103 { 0 }
16104 };
16105
16106 static int hotkey_letter;
16107
16108 static LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
16109 {
16110 struct recvd_message msg;
16111
16112 if (nCode == HC_ACTION)
16113 {
16114 KBDLLHOOKSTRUCT *kdbhookstruct = (KBDLLHOOKSTRUCT*)lParam;
16115
16116 msg.hwnd = 0;
16117 msg.message = wParam;
16118 msg.flags = kbd_hook|wparam|lparam;
16119 msg.wParam = kdbhookstruct->vkCode;
16120 msg.lParam = kdbhookstruct->flags;
16121 msg.descr = "KeyboardHookProc";
16122 add_message(&msg);
16123
16124 if (wParam == WM_KEYUP || wParam == WM_KEYDOWN)
16125 {
16126 ok(kdbhookstruct->vkCode == VK_LWIN || kdbhookstruct->vkCode == hotkey_letter,
16127 "unexpected keycode %x\n", kdbhookstruct->vkCode);
16128 }
16129 }
16130
16131 return CallNextHookEx(hKBD_hook, nCode, wParam, lParam);
16132 }
16133
16134 static void test_hotkey(void)
16135 {
16136 HWND test_window, taskbar_window;
16137 BOOL ret;
16138 MSG msg;
16139 DWORD queue_status;
16140 SHORT key_state;
16141
16142 SetLastError(0xdeadbeef);
16143 ret = UnregisterHotKey(NULL, 0);
16144 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16145 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16146 "unexpected error %d\n", GetLastError());
16147
16148 if (ret == TRUE)
16149 {
16150 skip("hotkeys not supported\n");
16151 return;
16152 }
16153
16154 test_window = CreateWindowExA(0, "HotkeyWindowClass", NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
16155 100, 100, 200, 200, 0, 0, 0, NULL);
16156
16157 flush_sequence();
16158
16159 SetLastError(0xdeadbeef);
16160 ret = UnregisterHotKey(test_window, 0);
16161 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16162 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16163 "unexpected error %d\n", GetLastError());
16164
16165 /* Search for a Windows Key + letter combination that hasn't been registered */
16166 for (hotkey_letter = 0x41; hotkey_letter <= 0x51; hotkey_letter ++)
16167 {
16168 SetLastError(0xdeadbeef);
16169 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
16170
16171 if (ret == TRUE)
16172 {
16173 break;
16174 }
16175 else
16176 {
16177 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16178 "unexpected error %d\n", GetLastError());
16179 }
16180 }
16181
16182 if (hotkey_letter == 0x52)
16183 {
16184 ok(0, "Couldn't find any free Windows Key + letter combination\n");
16185 goto end;
16186 }
16187
16188 hKBD_hook = SetWindowsHookExA(WH_KEYBOARD_LL, KeyboardHookProc, GetModuleHandleA(NULL), 0);
16189 if (!hKBD_hook) win_skip("WH_KEYBOARD_LL is not supported\n");
16190
16191 /* Same key combination, different id */
16192 SetLastError(0xdeadbeef);
16193 ret = RegisterHotKey(test_window, 4, MOD_WIN, hotkey_letter);
16194 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16195 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16196 "unexpected error %d\n", GetLastError());
16197
16198 /* Same key combination, different window */
16199 SetLastError(0xdeadbeef);
16200 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
16201 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16202 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16203 "unexpected error %d\n", GetLastError());
16204
16205 /* Register the same hotkey twice */
16206 SetLastError(0xdeadbeef);
16207 ret = RegisterHotKey(test_window, 5, MOD_WIN, hotkey_letter);
16208 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16209 ok(GetLastError() == ERROR_HOTKEY_ALREADY_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16210 "unexpected error %d\n", GetLastError());
16211
16212 /* Window on another thread */
16213 taskbar_window = FindWindowA("Shell_TrayWnd", NULL);
16214 if (!taskbar_window)
16215 {
16216 skip("no taskbar?\n");
16217 }
16218 else
16219 {
16220 SetLastError(0xdeadbeef);
16221 ret = RegisterHotKey(taskbar_window, 5, 0, hotkey_letter);
16222 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16223 ok(GetLastError() == ERROR_WINDOW_OF_OTHER_THREAD || broken(GetLastError() == 0xdeadbeef),
16224 "unexpected error %d\n", GetLastError());
16225 }
16226
16227 /* Inject the appropriate key sequence */
16228 keybd_event(VK_LWIN, 0, 0, 0);
16229 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16230 DispatchMessageA(&msg);
16231 ok_sequence(WmHotkeyPressLWIN, "window hotkey press LWIN", FALSE);
16232
16233 keybd_event(hotkey_letter, 0, 0, 0);
16234 queue_status = GetQueueStatus(QS_HOTKEY);
16235 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
16236 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16237 {
16238 if (msg.message == WM_HOTKEY)
16239 {
16240 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
16241 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16242 }
16243 DispatchMessageA(&msg);
16244 }
16245 ok_sequence(WmHotkeyPress, "window hotkey press", FALSE);
16246
16247 queue_status = GetQueueStatus(QS_HOTKEY);
16248 ok((queue_status & (QS_HOTKEY << 16)) == 0, "expected QS_HOTKEY << 16 cleared, got %x\n", queue_status);
16249
16250 key_state = GetAsyncKeyState(hotkey_letter);
16251 ok((key_state & 0x8000) == 0x8000, "unexpected key state %x\n", key_state);
16252
16253 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16254 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16255 DispatchMessageA(&msg);
16256 ok_sequence(WmHotkeyRelease, "window hotkey release", TRUE);
16257
16258 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16259 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16260 DispatchMessageA(&msg);
16261 ok_sequence(WmHotkeyReleaseLWIN, "window hotkey release LWIN", FALSE);
16262
16263 /* normal posted WM_HOTKEY messages set QS_HOTKEY */
16264 PostMessageA(test_window, WM_HOTKEY, 0, 0);
16265 queue_status = GetQueueStatus(QS_HOTKEY);
16266 ok((queue_status & (QS_HOTKEY << 16)) == QS_HOTKEY << 16, "expected QS_HOTKEY << 16 set, got %x\n", queue_status);
16267 queue_status = GetQueueStatus(QS_POSTMESSAGE);
16268 ok((queue_status & (QS_POSTMESSAGE << 16)) == QS_POSTMESSAGE << 16, "expected QS_POSTMESSAGE << 16 set, got %x\n", queue_status);
16269 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16270 DispatchMessageA(&msg);
16271 flush_sequence();
16272
16273 /* Send and process all messages at once */
16274 PostMessageA(test_window, WM_APP, 0, 0);
16275 keybd_event(VK_LWIN, 0, 0, 0);
16276 keybd_event(hotkey_letter, 0, 0, 0);
16277 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16278 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16279
16280 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16281 {
16282 if (msg.message == WM_HOTKEY)
16283 {
16284 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
16285 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16286 }
16287 DispatchMessageA(&msg);
16288 }
16289 ok_sequence(WmHotkeyCombined, "window hotkey combined", FALSE);
16290
16291 /* Register same hwnd/id with different key combination */
16292 ret = RegisterHotKey(test_window, 5, 0, hotkey_letter);
16293 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16294
16295 /* Previous key combination does not work */
16296 keybd_event(VK_LWIN, 0, 0, 0);
16297 keybd_event(hotkey_letter, 0, 0, 0);
16298 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16299 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16300
16301 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16302 DispatchMessageA(&msg);
16303 ok_sequence(WmHotkeyPrevious, "window hotkey previous", FALSE);
16304
16305 /* New key combination works */
16306 keybd_event(hotkey_letter, 0, 0, 0);
16307 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16308
16309 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16310 {
16311 if (msg.message == WM_HOTKEY)
16312 {
16313 ok(msg.hwnd == test_window, "unexpected hwnd %p\n", msg.hwnd);
16314 ok(msg.lParam == MAKELPARAM(0, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16315 }
16316 DispatchMessageA(&msg);
16317 }
16318 ok_sequence(WmHotkeyNew, "window hotkey new", FALSE);
16319
16320 /* Unregister hotkey properly */
16321 ret = UnregisterHotKey(test_window, 5);
16322 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16323
16324 /* Unregister hotkey again */
16325 SetLastError(0xdeadbeef);
16326 ret = UnregisterHotKey(test_window, 5);
16327 ok(ret == FALSE, "expected FALSE, got %i\n", ret);
16328 ok(GetLastError() == ERROR_HOTKEY_NOT_REGISTERED || broken(GetLastError() == 0xdeadbeef),
16329 "unexpected error %d\n", GetLastError());
16330
16331 /* Register thread hotkey */
16332 ret = RegisterHotKey(NULL, 5, MOD_WIN, hotkey_letter);
16333 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16334
16335 /* Inject the appropriate key sequence */
16336 keybd_event(VK_LWIN, 0, 0, 0);
16337 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16338 {
16339 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16340 DispatchMessageA(&msg);
16341 }
16342 ok_sequence(WmHotkeyPressLWIN, "thread hotkey press LWIN", FALSE);
16343
16344 keybd_event(hotkey_letter, 0, 0, 0);
16345 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16346 {
16347 if (msg.message == WM_HOTKEY)
16348 {
16349 struct recvd_message message;
16350 ok(msg.hwnd == NULL, "unexpected hwnd %p\n", msg.hwnd);
16351 ok(msg.lParam == MAKELPARAM(MOD_WIN, hotkey_letter), "unexpected WM_HOTKEY lparam %lx\n", msg.lParam);
16352 message.message = msg.message;
16353 message.flags = sent|wparam|lparam;
16354 message.wParam = msg.wParam;
16355 message.lParam = msg.lParam;
16356 message.descr = "test_hotkey thread message";
16357 add_message(&message);
16358 }
16359 else
16360 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16361 DispatchMessageA(&msg);
16362 }
16363 ok_sequence(WmHotkeyPress, "thread hotkey press", FALSE);
16364
16365 keybd_event(hotkey_letter, 0, KEYEVENTF_KEYUP, 0);
16366 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16367 {
16368 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16369 DispatchMessageA(&msg);
16370 }
16371 ok_sequence(WmHotkeyRelease, "thread hotkey release", TRUE);
16372
16373 keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);
16374 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
16375 {
16376 ok(msg.hwnd != NULL, "unexpected thread message %x\n", msg.message);
16377 DispatchMessageA(&msg);
16378 }
16379 ok_sequence(WmHotkeyReleaseLWIN, "thread hotkey release LWIN", FALSE);
16380
16381 /* Unregister thread hotkey */
16382 ret = UnregisterHotKey(NULL, 5);
16383 ok(ret == TRUE, "expected TRUE, got %i, err=%d\n", ret, GetLastError());
16384
16385 if (hKBD_hook) UnhookWindowsHookEx(hKBD_hook);
16386 hKBD_hook = NULL;
16387
16388 end:
16389 UnregisterHotKey(NULL, 5);
16390 UnregisterHotKey(test_window, 5);
16391 DestroyWindow(test_window);
16392 flush_sequence();
16393 }
16394
16395
16396 static const struct message WmSetFocus_1[] = {
16397 { HCBT_SETFOCUS, hook }, /* child */
16398 { HCBT_ACTIVATE, hook }, /* parent */
16399 { WM_QUERYNEWPALETTE, sent|wparam|lparam|parent|optional, 0, 0 },
16400 { WM_WINDOWPOSCHANGING, sent|parent, 0, SWP_NOSIZE|SWP_NOMOVE },
16401 { WM_ACTIVATEAPP, sent|wparam|parent, 1 },
16402 { WM_NCACTIVATE, sent|parent },
16403 { WM_GETTEXT, sent|defwinproc|parent|optional },
16404 { WM_GETTEXT, sent|defwinproc|parent|optional },
16405 { WM_ACTIVATE, sent|wparam|parent, 1 },
16406 { HCBT_SETFOCUS, hook }, /* parent */
16407 { WM_SETFOCUS, sent|defwinproc|parent },
16408 { WM_KILLFOCUS, sent|parent },
16409 { WM_SETFOCUS, sent },
16410 { 0 }
16411 };
16412 static const struct message WmSetFocus_2[] = {
16413 { HCBT_SETFOCUS, hook }, /* parent */
16414 { WM_KILLFOCUS, sent },
16415 { WM_SETFOCUS, sent|parent },
16416 { 0 }
16417 };
16418 static const struct message WmSetFocus_3[] = {
16419 { HCBT_SETFOCUS, hook }, /* child */
16420 { 0 }
16421 };
16422
16423 static void test_SetFocus(void)
16424 {
16425 HWND parent, old_parent, child, old_focus, old_active;
16426 MSG msg;
16427 struct wnd_event wnd_event;
16428 HANDLE hthread;
16429 DWORD ret, tid;
16430
16431 wnd_event.start_event = CreateEventW(NULL, 0, 0, NULL);
16432 ok(wnd_event.start_event != 0, "CreateEvent error %d\n", GetLastError());
16433 hthread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
16434 ok(hthread != 0, "CreateThread error %d\n", GetLastError());
16435 ret = WaitForSingleObject(wnd_event.start_event, INFINITE);
16436 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
16437 CloseHandle(wnd_event.start_event);
16438
16439 parent = CreateWindowExA(0, "TestParentClass", NULL, WS_OVERLAPPEDWINDOW,
16440 0, 0, 0, 0, 0, 0, 0, NULL);
16441 ok(parent != 0, "failed to create parent window\n");
16442 child = CreateWindowExA(0, "TestWindowClass", NULL, WS_CHILD,
16443 0, 0, 0, 0, parent, 0, 0, NULL);
16444 ok(child != 0, "failed to create child window\n");
16445
16446 trace("parent %p, child %p, thread window %p\n", parent, child, wnd_event.hwnd);
16447
16448 SetFocus(0);
16449 SetActiveWindow(0);
16450
16451 flush_events();
16452 flush_sequence();
16453
16454 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
16455 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
16456
16457 log_all_parent_messages++;
16458
16459 old_focus = SetFocus(child);
16460 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16461 ok_sequence(WmSetFocus_1, "SetFocus on a child window", TRUE);
16462 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
16463 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16464 ok(GetFocus() == child, "expected focus %p, got %p\n", child, GetFocus());
16465
16466 old_focus = SetFocus(parent);
16467 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16468 ok_sequence(WmSetFocus_2, "SetFocus on a parent window", FALSE);
16469 ok(old_focus == child, "expected old focus %p, got %p\n", child, old_focus);
16470 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16471 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16472
16473 SetLastError(0xdeadbeef);
16474 old_focus = SetFocus((HWND)0xdeadbeef);
16475 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
16476 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
16477 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16478 ok_sequence(WmEmptySeq, "SetFocus on an invalid window", FALSE);
16479 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
16480 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16481 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16482
16483 SetLastError(0xdeadbeef);
16484 old_focus = SetFocus(GetDesktopWindow());
16485 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
16486 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
16487 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16488 ok_sequence(WmEmptySeq, "SetFocus on a desktop window", TRUE);
16489 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
16490 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16491 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16492
16493 SetLastError(0xdeadbeef);
16494 old_focus = SetFocus(wnd_event.hwnd);
16495 ok(GetLastError() == ERROR_ACCESS_DENIED /* Vista+ */ ||
16496 broken(GetLastError() == 0xdeadbeef), "expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
16497 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16498 ok_sequence(WmEmptySeq, "SetFocus on another thread window", TRUE);
16499 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
16500 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16501 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16502
16503 SetLastError(0xdeadbeef);
16504 old_active = SetActiveWindow((HWND)0xdeadbeef);
16505 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE || broken(GetLastError() == 0xdeadbeef),
16506 "expected ERROR_INVALID_WINDOW_HANDLE, got %d\n", GetLastError());
16507 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16508 ok_sequence(WmEmptySeq, "SetActiveWindow on an invalid window", FALSE);
16509 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
16510 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16511 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16512
16513 SetLastError(0xdeadbeef);
16514 old_active = SetActiveWindow(GetDesktopWindow());
16515 todo_wine
16516 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
16517 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16518 ok_sequence(WmEmptySeq, "SetActiveWindow on a desktop window", TRUE);
16519 ok(old_active == 0, "expected old focus 0, got %p\n", old_focus);
16520 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16521 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16522
16523 SetLastError(0xdeadbeef);
16524 old_active = SetActiveWindow(wnd_event.hwnd);
16525 todo_wine
16526 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
16527 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16528 ok_sequence(WmEmptySeq, "SetActiveWindow on another thread window", TRUE);
16529 ok(old_active == 0, "expected old focus 0, got %p\n", old_active);
16530 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16531 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16532
16533 SetLastError(0xdeadbeef);
16534 ret = AttachThreadInput(GetCurrentThreadId(), tid, TRUE);
16535 ok(ret, "AttachThreadInput error %d\n", GetLastError());
16536
16537 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16538 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16539
16540 flush_events();
16541 flush_sequence();
16542
16543 old_focus = SetFocus(wnd_event.hwnd);
16544 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16545 ok(old_focus == wnd_event.hwnd, "expected old focus %p, got %p\n", wnd_event.hwnd, old_focus);
16546 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
16547 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
16548
16549 old_focus = SetFocus(parent);
16550 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16551 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
16552 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16553 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16554
16555 flush_events();
16556 flush_sequence();
16557
16558 old_active = SetActiveWindow(wnd_event.hwnd);
16559 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16560 ok(old_active == parent, "expected old focus %p, got %p\n", parent, old_active);
16561 ok(GetActiveWindow() == wnd_event.hwnd, "expected active %p, got %p\n", wnd_event.hwnd, GetActiveWindow());
16562 ok(GetFocus() == wnd_event.hwnd, "expected focus %p, got %p\n", wnd_event.hwnd, GetFocus());
16563
16564 SetLastError(0xdeadbeef);
16565 ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE);
16566 ok(ret, "AttachThreadInput error %d\n", GetLastError());
16567
16568 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
16569 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
16570
16571 old_parent = SetParent(child, GetDesktopWindow());
16572 ok(old_parent == parent, "expected old parent %p, got %p\n", parent, old_parent);
16573
16574 ok(GetActiveWindow() == 0, "expected active 0, got %p\n", GetActiveWindow());
16575 ok(GetFocus() == 0, "expected focus 0, got %p\n", GetFocus());
16576
16577 old_focus = SetFocus(parent);
16578 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16579 ok(old_focus == parent, "expected old focus %p, got %p\n", parent, old_focus);
16580 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16581 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16582
16583 flush_events();
16584 flush_sequence();
16585
16586 SetLastError(0xdeadbeef);
16587 old_focus = SetFocus(child);
16588 todo_wine
16589 ok(GetLastError() == ERROR_INVALID_PARAMETER /* Vista+ */ ||
16590 broken(GetLastError() == 0) /* XP */ ||
16591 broken(GetLastError() == 0xdeadbeef), "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
16592 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16593 ok_sequence(WmSetFocus_3, "SetFocus on a child window", TRUE);
16594 ok(old_focus == 0, "expected old focus 0, got %p\n", old_focus);
16595 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16596 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16597
16598 SetLastError(0xdeadbeef);
16599 old_active = SetActiveWindow(child);
16600 ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
16601 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
16602 ok_sequence(WmEmptySeq, "SetActiveWindow on a child window", FALSE);
16603 ok(old_active == parent, "expected old active %p, got %p\n", parent, old_active);
16604 ok(GetActiveWindow() == parent, "expected active %p, got %p\n", parent, GetActiveWindow());
16605 ok(GetFocus() == parent, "expected focus %p, got %p\n", parent, GetFocus());
16606
16607 log_all_parent_messages--;
16608
16609 DestroyWindow(child);
16610 DestroyWindow(parent);
16611
16612 ret = PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0);
16613 ok(ret, "PostMessage(WM_QUIT) error %d\n", GetLastError());
16614 ret = WaitForSingleObject(hthread, INFINITE);
16615 ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
16616 CloseHandle(hthread);
16617 }
16618
16619 static const struct message WmSetLayeredStyle[] = {
16620 { WM_STYLECHANGING, sent },
16621 { WM_STYLECHANGED, sent },
16622 { WM_GETTEXT, sent|defwinproc|optional },
16623 { 0 }
16624 };
16625
16626 static const struct message WmSetLayeredStyle2[] = {
16627 { WM_STYLECHANGING, sent },
16628 { WM_STYLECHANGED, sent },
16629 { WM_WINDOWPOSCHANGING, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE },
16630 { WM_NCCALCSIZE, sent|optional|wparam|defwinproc, 1 },
16631 { WM_WINDOWPOSCHANGED, sent|optional|wparam|defwinproc, SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE },
16632 { WM_MOVE, sent|optional|defwinproc|wparam, 0 },
16633 { WM_SIZE, sent|optional|defwinproc|wparam, SIZE_RESTORED },
16634 { 0 }
16635 };
16636
16637 struct layered_window_info
16638 {
16639 HWND hwnd;
16640 HDC hdc;
16641 SIZE size;
16642 HANDLE event;
16643 BOOL ret;
16644 };
16645
16646 static DWORD CALLBACK update_layered_proc( void *param )
16647 {
16648 struct layered_window_info *info = param;
16649 POINT src = { 0, 0 };
16650
16651 info->ret = pUpdateLayeredWindow( info->hwnd, 0, NULL, &info->size,
16652 info->hdc, &src, 0, NULL, ULW_OPAQUE );
16653 ok( info->ret, "failed\n");
16654 SetEvent( info->event );
16655 return 0;
16656 }
16657
16658 static void test_layered_window(void)
16659 {
16660 HWND hwnd;
16661 HDC hdc;
16662 HBITMAP bmp;
16663 BOOL ret;
16664 SIZE size;
16665 POINT pos, src;
16666 RECT rect, client;
16667 HANDLE thread;
16668 DWORD tid;
16669 struct layered_window_info info;
16670
16671 if (!pUpdateLayeredWindow)
16672 {
16673 win_skip( "UpdateLayeredWindow not supported\n" );
16674 return;
16675 }
16676
16677 hdc = CreateCompatibleDC( 0 );
16678 bmp = CreateCompatibleBitmap( hdc, 300, 300 );
16679 SelectObject( hdc, bmp );
16680
16681 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_CAPTION | WS_THICKFRAME | WS_SYSMENU,
16682 100, 100, 300, 300, 0, 0, 0, NULL);
16683 ok( hwnd != 0, "failed to create window\n" );
16684 ShowWindow( hwnd, SW_SHOWNORMAL );
16685 UpdateWindow( hwnd );
16686 flush_events();
16687 flush_sequence();
16688
16689 GetWindowRect( hwnd, &rect );
16690 GetClientRect( hwnd, &client );
16691 ok( client.right < rect.right - rect.left, "wrong client area\n" );
16692 ok( client.bottom < rect.bottom - rect.top, "wrong client area\n" );
16693
16694 src.x = src.y = 0;
16695 pos.x = pos.y = 300;
16696 size.cx = size.cy = 250;
16697 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16698 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
16699 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
16700 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
16701 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
16702
16703 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16704 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
16705 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
16706 GetWindowRect( hwnd, &rect );
16707 ok( rect.left == 300 && rect.top == 300 && rect.right == 550 && rect.bottom == 550,
16708 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16709 GetClientRect( hwnd, &rect );
16710 ok( rect.right == client.right - 50 && rect.bottom == client.bottom - 50,
16711 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16712
16713 size.cx = 150;
16714 pos.y = 200;
16715 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16716 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
16717 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
16718 GetWindowRect( hwnd, &rect );
16719 ok( rect.left == 300 && rect.top == 200 && rect.right == 450 && rect.bottom == 450,
16720 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16721 GetClientRect( hwnd, &rect );
16722 ok( rect.right == client.right - 150 && rect.bottom == client.bottom - 50,
16723 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16724
16725 SetWindowLongA( hwnd, GWL_STYLE,
16726 GetWindowLongA(hwnd, GWL_STYLE) & ~(WS_CAPTION | WS_THICKFRAME | WS_SYSMENU) );
16727 ok_sequence( WmSetLayeredStyle2, "WmSetLayeredStyle2", FALSE );
16728
16729 size.cx = 200;
16730 pos.x = 200;
16731 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16732 ok( ret, "UpdateLayeredWindow failed err %u\n", GetLastError() );
16733 ok_sequence( WmEmptySeq, "UpdateLayeredWindow", FALSE );
16734 GetWindowRect( hwnd, &rect );
16735 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
16736 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16737 GetClientRect( hwnd, &rect );
16738 ok( (rect.right == 200 && rect.bottom == 250) ||
16739 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
16740 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16741
16742 size.cx = 0;
16743 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16744 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
16745 ok( GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_MR_MID_NOT_FOUND) ||
16746 broken(GetLastError() == ERROR_GEN_FAILURE) /* win7 */, "wrong error %u\n", GetLastError() );
16747 size.cx = 1;
16748 size.cy = -1;
16749 ret = pUpdateLayeredWindow( hwnd, 0, &pos, &size, hdc, &src, 0, NULL, ULW_OPAQUE );
16750 ok( !ret, "UpdateLayeredWindow should fail on non-layered window\n" );
16751 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
16752
16753 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED );
16754 ok_sequence( WmSetLayeredStyle, "WmSetLayeredStyle", FALSE );
16755 GetWindowRect( hwnd, &rect );
16756 ok( rect.left == 200 && rect.top == 200 && rect.right == 400 && rect.bottom == 450,
16757 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16758 GetClientRect( hwnd, &rect );
16759 ok( (rect.right == 200 && rect.bottom == 250) ||
16760 broken(rect.right == client.right - 100 && rect.bottom == client.bottom - 50),
16761 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16762
16763 SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
16764 info.hwnd = hwnd;
16765 info.hdc = hdc;
16766 info.size.cx = 250;
16767 info.size.cy = 300;
16768 info.event = CreateEventA( NULL, TRUE, FALSE, NULL );
16769 info.ret = FALSE;
16770 thread = CreateThread( NULL, 0, update_layered_proc, &info, 0, &tid );
16771 ok( WaitForSingleObject( info.event, 1000 ) == 0, "wait failed\n" );
16772 ok( info.ret, "UpdateLayeredWindow failed in other thread\n" );
16773 WaitForSingleObject( thread, 1000 );
16774 CloseHandle( thread );
16775 GetWindowRect( hwnd, &rect );
16776 ok( rect.left == 200 && rect.top == 200 && rect.right == 450 && rect.bottom == 500,
16777 "wrong window rect %s\n", wine_dbgstr_rect( &rect ));
16778 GetClientRect( hwnd, &rect );
16779 ok( (rect.right == 250 && rect.bottom == 300) ||
16780 broken(rect.right == client.right - 50 && rect.bottom == client.bottom),
16781 "wrong client rect %s\n", wine_dbgstr_rect( &rect ));
16782
16783 DestroyWindow( hwnd );
16784 DeleteDC( hdc );
16785 DeleteObject( bmp );
16786 }
16787
16788 static HMENU hpopupmenu;
16789
16790 static LRESULT WINAPI cancel_popup_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
16791 {
16792 if (ignore_message( message )) return 0;
16793
16794 switch (message) {
16795 case WM_ENTERIDLE:
16796 todo_wine ok(GetCapture() == hwnd, "expected %p, got %p\n", hwnd, GetCapture());
16797 EndMenu();
16798 break;
16799 case WM_INITMENU:
16800 case WM_INITMENUPOPUP:
16801 case WM_UNINITMENUPOPUP:
16802 ok((HMENU)wParam == hpopupmenu, "expected %p, got %lx\n", hpopupmenu, wParam);
16803 break;
16804 case WM_CAPTURECHANGED:
16805 todo_wine ok(!lParam || (HWND)lParam == hwnd, "lost capture to %lx\n", lParam);
16806 break;
16807 }
16808
16809 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
16810 }
16811
16812 static LRESULT WINAPI cancel_init_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
16813 {
16814 if (ignore_message( message )) return 0;
16815
16816 switch (message) {
16817 case WM_ENTERMENULOOP:
16818 ok(EndMenu() == TRUE, "EndMenu() failed\n");
16819 break;
16820 }
16821
16822 return MsgCheckProc (FALSE, hwnd, message, wParam, lParam);
16823 }
16824
16825 static void test_TrackPopupMenu(void)
16826 {
16827 MSG msg;
16828 HWND hwnd;
16829 BOOL ret;
16830
16831 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
16832 0, 0, 1, 1, 0,
16833 NULL, NULL, 0);
16834 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
16835
16836 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
16837
16838 hpopupmenu = CreatePopupMenu();
16839 ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
16840
16841 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 1");
16842 AppendMenuA(hpopupmenu, MF_STRING, 100, "item 2");
16843
16844 flush_events();
16845 flush_sequence();
16846 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
16847 ok_sequence(WmTrackPopupMenu, "TrackPopupMenu", TRUE);
16848 ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError());
16849
16850 /* Test popup closing with an ESC-press */
16851 flush_events();
16852 PostMessageW(hwnd, WM_KEYDOWN, VK_ESCAPE, 0);
16853 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
16854 ok(ret == 1, "TrackPopupMenu failed with error %i\n", GetLastError());
16855 PostQuitMessage(0);
16856 flush_sequence();
16857 while ( PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) )
16858 {
16859 TranslateMessage(&msg);
16860 DispatchMessageA(&msg);
16861 }
16862 ok_sequence(WmTrackPopupMenuEsc, "TrackPopupMenuEsc", FALSE); /* Shouldn't get any message */
16863
16864 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_init_proc);
16865
16866 flush_events();
16867 flush_sequence();
16868 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
16869 ok_sequence(WmTrackPopupMenuAbort, "WmTrackPopupMenuAbort", TRUE);
16870 ok(ret == TRUE, "TrackPopupMenu failed\n");
16871
16872 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
16873
16874 SetCapture(hwnd);
16875
16876 flush_events();
16877 flush_sequence();
16878 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
16879 ok_sequence(WmTrackPopupMenuCapture, "TrackPopupMenuCapture", TRUE);
16880 ok(ret == 1, "TrackPopupMenuCapture failed with error %i\n", GetLastError());
16881
16882 DestroyMenu(hpopupmenu);
16883 DestroyWindow(hwnd);
16884 }
16885
16886 static void test_TrackPopupMenuEmpty(void)
16887 {
16888 HWND hwnd;
16889 BOOL ret;
16890
16891 hwnd = CreateWindowExA(0, "TestWindowClass", NULL, 0,
16892 0, 0, 1, 1, 0,
16893 NULL, NULL, 0);
16894 ok(hwnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
16895
16896 SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)cancel_popup_proc);
16897
16898 hpopupmenu = CreatePopupMenu();
16899 ok(hpopupmenu != NULL, "CreateMenu failed with error %d\n", GetLastError());
16900
16901 flush_events();
16902 flush_sequence();
16903 ret = TrackPopupMenu(hpopupmenu, 0, 100,100, 0, hwnd, NULL);
16904 ok_sequence(WmTrackPopupMenuEmpty, "TrackPopupMenuEmpty", TRUE);
16905 ok(ret == 0, "TrackPopupMenu succeeded\n");
16906
16907 DestroyMenu(hpopupmenu);
16908 DestroyWindow(hwnd);
16909 }
16910
16911 static const struct message send_message_1[] = {
16912 { WM_USER+2, sent|wparam|lparam, 0, 0 },
16913 { WM_USER, sent|wparam|lparam, 0, 0 },
16914 { 0 }
16915 };
16916 static const struct message send_message_2[] = {
16917 { WM_USER+4, sent|wparam|lparam, 0, 0 },
16918 { 0 }
16919 };
16920 static const struct message send_message_3[] = {
16921 { WM_USER+3, sent|wparam|lparam, 0, 0 },
16922 { 0 }
16923 };
16924 static const struct message send_message_4[] = {
16925 { WM_USER+1, sent|wparam|lparam, 0, 0 },
16926 { 0 }
16927 };
16928
16929 static DWORD WINAPI SendMessage_thread_1(void *param)
16930 {
16931 struct wnd_event *wnd_event = param;
16932
16933 trace("thread: starting\n");
16934 WaitForSingleObject(wnd_event->start_event, INFINITE);
16935
16936 trace("thread: call PostMessage\n");
16937 PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
16938
16939 trace("thread: call PostMessage\n");
16940 PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
16941
16942 trace("thread: call SendMessage\n");
16943 SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
16944
16945 trace("thread: call SendMessage\n");
16946 SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
16947
16948 return 0;
16949 }
16950
16951 static DWORD WINAPI SendMessage_thread_2(void *param)
16952 {
16953 struct wnd_event *wnd_event = param;
16954
16955 trace("thread: starting\n");
16956 WaitForSingleObject(wnd_event->start_event, INFINITE);
16957
16958 trace("thread: call PostMessage\n");
16959 PostMessageA(wnd_event->hwnd, WM_USER, 0, 0);
16960
16961 trace("thread: call PostMessage\n");
16962 PostMessageA(wnd_event->hwnd, WM_USER+1, 0, 0);
16963
16964 /* this leads to sending an internal message under Wine */
16965 trace("thread: call SetParent\n");
16966 SetParent(wnd_event->hwnd, wnd_event->hwnd);
16967
16968 trace("thread: call SendMessage\n");
16969 SendMessageA(wnd_event->hwnd, WM_USER+2, 0, 0);
16970
16971 trace("thread: call SendMessage\n");
16972 SendMessageA(wnd_event->hwnd, WM_USER+3, 0, 0);
16973
16974 return 0;
16975 }
16976
16977 static void test_SendMessage_other_thread(int thread_n)
16978 {
16979 DWORD qs_all_input = QS_ALLINPUT & ~QS_RAWINPUT;
16980 HANDLE hthread;
16981 struct wnd_event wnd_event;
16982 DWORD tid, ret;
16983 MSG msg;
16984
16985 wnd_event.start_event = CreateEventA(NULL, 0, 0, NULL);
16986
16987 wnd_event.hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW,
16988 100, 100, 200, 200, 0, 0, 0, NULL);
16989 ok(wnd_event.hwnd != 0, "CreateWindowEx failed\n");
16990
16991 hthread = CreateThread(NULL, 0, thread_n == 1 ? SendMessage_thread_1 : SendMessage_thread_2, &wnd_event, 0, &tid);
16992 ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError());
16993 CloseHandle(hthread);
16994
16995 flush_events();
16996 flush_sequence();
16997
16998 ret = GetQueueStatus(QS_SENDMESSAGE);
16999 ok(ret == 0, "wrong status %08x\n", ret);
17000
17001 SetEvent(wnd_event.start_event);
17002
17003 /* wait for other thread's SendMessage */
17004 for (;;)
17005 {
17006 ret = GetQueueStatus(QS_SENDMESSAGE);
17007 if (ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE)) break;
17008 Sleep(50);
17009 }
17010
17011 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17012 ok(ret == MAKELONG(QS_POSTMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08x\n", ret);
17013
17014 trace("main: call GetMessage\n");
17015 GetMessageA(&msg, 0, 0, 0);
17016 ok(msg.message == WM_USER, "expected WM_USER, got %04x\n", msg.message);
17017 DispatchMessageA(&msg);
17018 ok_sequence(send_message_1, "SendMessage from other thread 1", thread_n == 2);
17019
17020 /* intentionally yield */
17021 MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
17022
17023 trace("main: call SendMessage\n");
17024 SendMessageA(wnd_event.hwnd, WM_USER+4, 0, 0);
17025 ok_sequence(send_message_2, "SendMessage from other thread 2", FALSE);
17026
17027 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17028 ok(ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE|QS_POSTMESSAGE), "wrong status %08x\n", ret);
17029
17030 trace("main: call PeekMessage\n");
17031 ok(PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "PeekMessage should not fail\n");
17032 ok(msg.message == WM_USER+1, "expected WM_USER+1, got %04x\n", msg.message);
17033 ok_sequence(send_message_3, "SendMessage from other thread 3", thread_n == 2);
17034
17035 trace("main: call PeekMessage\n");
17036 ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should not fail\n");
17037 ok(msg.message == WM_USER+1, "expected WM_USER+1, got %04x\n", msg.message);
17038 DispatchMessageA(&msg);
17039 ok_sequence(send_message_4, "SendMessage from other thread 4", FALSE);
17040
17041 /* intentionally yield */
17042 MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
17043
17044 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17045 /* FIXME: remove once Wine is fixed */
17046 todo_wine_if (thread_n == 2)
17047 ok(ret == 0, "wrong status %08x\n", ret);
17048
17049 trace("main: call PeekMessage\n");
17050 ok(!PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should fail\n");
17051 ok_sequence(WmEmptySeq, "SendMessage from other thread 5", thread_n == 2);
17052
17053 ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
17054 ok(ret == 0, "wrong status %08x\n", ret);
17055
17056 trace("main: call DestroyWindow\n");
17057 DestroyWindow(msg.hwnd);
17058
17059 flush_events();
17060 flush_sequence();
17061 }
17062
17063 static LRESULT CALLBACK insendmessage_wnd_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
17064 {
17065 DWORD flags = InSendMessageEx( NULL );
17066 BOOL ret;
17067
17068 switch (msg)
17069 {
17070 case WM_USER:
17071 ok( flags == ISMEX_SEND, "wrong flags %x\n", flags );
17072 ok( InSendMessage(), "InSendMessage returned false\n" );
17073 ret = ReplyMessage( msg );
17074 ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
17075 flags = InSendMessageEx( NULL );
17076 ok( flags == (ISMEX_SEND | ISMEX_REPLIED), "wrong flags %x\n", flags );
17077 ok( InSendMessage(), "InSendMessage returned false\n" );
17078 break;
17079 case WM_USER + 1:
17080 ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags );
17081 ok( InSendMessage(), "InSendMessage returned false\n" );
17082 ret = ReplyMessage( msg );
17083 ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
17084 flags = InSendMessageEx( NULL );
17085 ok( flags == ISMEX_NOTIFY, "wrong flags %x\n", flags );
17086 ok( InSendMessage(), "InSendMessage returned false\n" );
17087 break;
17088 case WM_USER + 2:
17089 ok( flags == ISMEX_CALLBACK, "wrong flags %x\n", flags );
17090 ok( InSendMessage(), "InSendMessage returned false\n" );
17091 ret = ReplyMessage( msg );
17092 ok( ret, "ReplyMessage failed err %u\n", GetLastError() );
17093 flags = InSendMessageEx( NULL );
17094 ok( flags == (ISMEX_CALLBACK | ISMEX_REPLIED) || flags == ISMEX_SEND, "wrong flags %x\n", flags );
17095 ok( InSendMessage(), "InSendMessage returned false\n" );
17096 break;
17097 case WM_USER + 3:
17098 ok( flags == ISMEX_NOSEND, "wrong flags %x\n", flags );
17099 ok( !InSendMessage(), "InSendMessage returned true\n" );
17100 ret = ReplyMessage( msg );
17101 ok( !ret, "ReplyMessage succeeded\n" );
17102 break;
17103 }
17104
17105 return DefWindowProcA( hwnd, msg, wp, lp );
17106 }
17107
17108 static void CALLBACK msg_callback( HWND hwnd, UINT msg, ULONG_PTR arg, LRESULT result )
17109 {
17110 ok( msg == WM_USER + 2, "wrong msg %x\n", msg );
17111 ok( result == WM_USER + 2, "wrong result %lx\n", result );
17112 }
17113
17114 static DWORD WINAPI send_message_thread( void *arg )
17115 {
17116 HWND win = arg;
17117
17118 SendMessageA( win, WM_USER, 0, 0 );
17119 SendNotifyMessageA( win, WM_USER + 1, 0, 0 );
17120 SendMessageCallbackA( win, WM_USER + 2, 0, 0, msg_callback, 0 );
17121 PostMessageA( win, WM_USER + 3, 0, 0 );
17122 PostMessageA( win, WM_QUIT, 0, 0 );
17123 return 0;
17124 }
17125
17126 static void test_InSendMessage(void)
17127 {
17128 WNDCLASSA cls;
17129 HWND win;
17130 MSG msg;
17131 HANDLE thread;
17132 DWORD tid;
17133
17134 memset(&cls, 0, sizeof(cls));
17135 cls.lpfnWndProc = insendmessage_wnd_proc;
17136 cls.hInstance = GetModuleHandleA(NULL);
17137 cls.lpszClassName = "InSendMessage_test";
17138 RegisterClassA(&cls);
17139
17140 win = CreateWindowA( "InSendMessage_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0 );
17141 ok( win != NULL, "CreateWindow failed: %d\n", GetLastError() );
17142
17143 thread = CreateThread( NULL, 0, send_message_thread, win, 0, &tid );
17144 ok( thread != NULL, "CreateThread failed: %d\n", GetLastError() );
17145
17146 while (GetMessageA(&msg, NULL, 0, 0)) DispatchMessageA( &msg );
17147
17148 ok( WaitForSingleObject( thread, 30000 ) == WAIT_OBJECT_0, "WaitForSingleObject failed\n" );
17149 CloseHandle( thread );
17150
17151 DestroyWindow( win );
17152 UnregisterClassA( "InSendMessage_test", GetModuleHandleA(NULL) );
17153 }
17154
17155 static const struct message DoubleSetCaptureSeq[] =
17156 {
17157 { WM_CAPTURECHANGED, sent },
17158 { 0 }
17159 };
17160
17161 static void test_DoubleSetCapture(void)
17162 {
17163 HWND hwnd;
17164
17165 hwnd = CreateWindowExA(0, "TestWindowClass", "Test DoubleSetCapture",
17166 WS_OVERLAPPEDWINDOW | WS_VISIBLE,
17167 100, 100, 200, 200, 0, 0, 0, NULL);
17168 ok (hwnd != 0, "Failed to create overlapped window\n");
17169
17170 ShowWindow( hwnd, SW_SHOW );
17171 UpdateWindow( hwnd );
17172 flush_events();
17173 flush_sequence();
17174
17175 SetCapture( hwnd );
17176 SetCapture( hwnd );
17177 ok_sequence(DoubleSetCaptureSeq, "SetCapture( hwnd ) twice", FALSE);
17178
17179 DestroyWindow(hwnd);
17180 }
17181
17182 static void init_funcs(void)
17183 {
17184 HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
17185
17186 #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f)
17187 X(ActivateActCtx);
17188 X(CreateActCtxW);
17189 X(DeactivateActCtx);
17190 X(GetCurrentActCtx);
17191 X(QueryActCtxW);
17192 X(ReleaseActCtx);
17193 #undef X
17194 }
17195
17196 #ifndef __REACTOS__
17197 START_TEST(msg)
17198 {
17199 char **test_argv;
17200 BOOL ret;
17201 BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
17202 HMODULE hModuleImm32;
17203 BOOL (WINAPI *pImmDisableIME)(DWORD);
17204 int argc;
17205
17206 init_funcs();
17207
17208 argc = winetest_get_mainargs( &test_argv );
17209 if (argc >= 3)
17210 {
17211 unsigned int arg;
17212 /* Child process. */
17213 sscanf (test_argv[2], "%d", (unsigned int *) &arg);
17214 do_wait_idle_child( arg );
17215 return;
17216 }
17217
17218 InitializeCriticalSection( &sequence_cs );
17219 init_procs();
17220
17221 hModuleImm32 = LoadLibraryA("imm32.dll");
17222 if (hModuleImm32) {
17223 pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
17224 if (pImmDisableIME)
17225 pImmDisableIME(0);
17226 }
17227 pImmDisableIME = NULL;
17228 FreeLibrary(hModuleImm32);
17229
17230 if (!RegisterWindowClasses()) assert(0);
17231
17232 if (pSetWinEventHook)
17233 {
17234 hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
17235 GetModuleHandleA(0), win_event_proc,
17236 0, GetCurrentThreadId(),
17237 WINEVENT_INCONTEXT);
17238 if (pIsWinEventHookInstalled && hEvent_hook)
17239 {
17240 UINT event;
17241 for (event = EVENT_MIN; event <= EVENT_MAX; event++)
17242 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
17243 }
17244 }
17245 if (!hEvent_hook) win_skip( "no win event hook support\n" );
17246
17247 cbt_hook_thread_id = GetCurrentThreadId();
17248 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
17249 if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
17250
17251 test_winevents();
17252
17253 /* Fix message sequences before removing 4 lines below */
17254 if (pUnhookWinEvent && hEvent_hook)
17255 {
17256 ret = pUnhookWinEvent(hEvent_hook);
17257 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
17258 pUnhookWinEvent = 0;
17259 }
17260 hEvent_hook = 0;
17261
17262 test_SendMessage_other_thread(1);
17263 test_SendMessage_other_thread(2);
17264 test_InSendMessage();
17265 test_SetFocus();
17266 test_SetParent();
17267 test_PostMessage();
17268 test_broadcast();
17269 test_ShowWindow();
17270 test_PeekMessage();
17271 test_PeekMessage2();
17272 test_PeekMessage3();
17273 test_WaitForInputIdle( test_argv[0] );
17274 test_scrollwindowex();
17275 test_messages();
17276 test_setwindowpos();
17277 test_showwindow();
17278 invisible_parent_tests();
17279 test_mdi_messages();
17280 test_button_messages();
17281 test_autoradio_BM_CLICK();
17282 test_autoradio_kbd_move();
17283 test_static_messages();
17284 test_listbox_messages();
17285 test_combobox_messages();
17286 test_wmime_keydown_message();
17287 test_paint_messages();
17288 test_interthread_messages();
17289 test_message_conversion();
17290 test_accelerators();
17291 test_timers();
17292 test_timers_no_wnd();
17293 test_timers_exceptions();
17294 if (hCBT_hook)
17295 {
17296 test_set_hook();
17297 test_recursive_hook();
17298 }
17299 test_DestroyWindow();
17300 test_DispatchMessage();
17301 test_SendMessageTimeout();
17302 test_edit_messages();
17303 test_quit_message();
17304 test_notify_message();
17305 test_SetActiveWindow();
17306
17307 if (!pTrackMouseEvent)
17308 win_skip("TrackMouseEvent is not available\n");
17309 else
17310 test_TrackMouseEvent();
17311
17312 test_SetWindowRgn();
17313 test_sys_menu();
17314 test_dialog_messages();
17315 test_EndDialog();
17316 test_nullCallback();
17317 test_dbcs_wm_char();
17318 test_unicode_wm_char();
17319 test_menu_messages();
17320 test_paintingloop();
17321 test_defwinproc();
17322 test_clipboard_viewers();
17323 test_keyflags();
17324 test_hotkey();
17325 test_layered_window();
17326 test_TrackPopupMenu();
17327 test_TrackPopupMenuEmpty();
17328 test_DoubleSetCapture();
17329 /* keep it the last test, under Windows it tends to break the tests
17330 * which rely on active/foreground windows being correct.
17331 */
17332 test_SetForegroundWindow();
17333
17334 UnhookWindowsHookEx(hCBT_hook);
17335 if (pUnhookWinEvent && hEvent_hook)
17336 {
17337 ret = pUnhookWinEvent(hEvent_hook);
17338 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
17339 SetLastError(0xdeadbeef);
17340 ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
17341 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
17342 GetLastError() == 0xdeadbeef, /* Win9x */
17343 "unexpected error %d\n", GetLastError());
17344 }
17345 DeleteCriticalSection( &sequence_cs );
17346 }
17347 #endif /* __REACTOS__ */
17348
17349 static void init_tests()
17350 {
17351 HMODULE hModuleImm32;
17352 BOOL (WINAPI *pImmDisableIME)(DWORD);
17353
17354 init_funcs();
17355
17356 InitializeCriticalSection( &sequence_cs );
17357 init_procs();
17358
17359 hModuleImm32 = LoadLibraryA("imm32.dll");
17360 if (hModuleImm32) {
17361 pImmDisableIME = (void *)GetProcAddress(hModuleImm32, "ImmDisableIME");
17362 if (pImmDisableIME)
17363 pImmDisableIME(0);
17364 }
17365 pImmDisableIME = NULL;
17366 FreeLibrary(hModuleImm32);
17367
17368 if (!RegisterWindowClasses()) assert(0);
17369
17370 cbt_hook_thread_id = GetCurrentThreadId();
17371 hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId());
17372 if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
17373 }
17374
17375 static void cleanup_tests()
17376 {
17377 BOOL ret;
17378 UnhookWindowsHookEx(hCBT_hook);
17379 if (pUnhookWinEvent && hEvent_hook)
17380 {
17381 ret = pUnhookWinEvent(hEvent_hook);
17382 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
17383 SetLastError(0xdeadbeef);
17384 ok(!pUnhookWinEvent(hEvent_hook), "UnhookWinEvent succeeded\n");
17385 ok(GetLastError() == ERROR_INVALID_HANDLE || /* Win2k */
17386 GetLastError() == 0xdeadbeef, /* Win9x */
17387 "unexpected error %d\n", GetLastError());
17388 }
17389 DeleteCriticalSection( &sequence_cs );
17390
17391 }
17392
17393 START_TEST(msg_queue)
17394 {
17395 int argc;
17396 char **test_argv;
17397 argc = winetest_get_mainargs( &test_argv );
17398 if (argc >= 3)
17399 {
17400 unsigned int arg;
17401 /* Child process. */
17402 sscanf (test_argv[2], "%d", (unsigned int *) &arg);
17403 do_wait_idle_child( arg );
17404 return;
17405 }
17406
17407 init_tests();
17408 test_SendMessage_other_thread(1);
17409 test_SendMessage_other_thread(2);
17410 test_InSendMessage();
17411 test_PostMessage();
17412 test_broadcast();
17413 test_PeekMessage();
17414 test_PeekMessage2();
17415 test_PeekMessage3();
17416 test_interthread_messages();
17417 test_DispatchMessage();
17418 test_SendMessageTimeout();
17419 test_quit_message();
17420 test_notify_message();
17421 test_WaitForInputIdle( test_argv[0] );
17422 test_DestroyWindow();
17423 cleanup_tests();
17424 }
17425
17426 START_TEST(msg_messages)
17427 {
17428 init_tests();
17429 test_message_conversion();
17430 test_messages();
17431 test_wmime_keydown_message();
17432 test_nullCallback();
17433 test_dbcs_wm_char();
17434 test_unicode_wm_char();
17435 test_defwinproc();
17436 cleanup_tests();
17437 }
17438
17439 START_TEST(msg_focus)
17440 {
17441 init_tests();
17442
17443 test_SetFocus();
17444
17445 /* HACK: For some reason the tests fail on Windows if run consecutively.
17446 * Putting these in between helps, and is essentially what happens in the
17447 * "normal" msg test. */
17448 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
17449 flush_events();
17450
17451 test_SetActiveWindow();
17452
17453 /* HACK */
17454 keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
17455 flush_events();
17456
17457 test_DoubleSetCapture();
17458
17459 /* keep it the last test, under Windows it tends to break the tests
17460 * which rely on active/foreground windows being correct.
17461 */
17462 test_SetForegroundWindow();
17463 cleanup_tests();
17464 }
17465
17466 START_TEST(msg_winpos)
17467 {
17468 init_tests();
17469 test_SetParent();
17470 test_ShowWindow();
17471 test_setwindowpos();
17472 test_showwindow();
17473 test_SetWindowRgn();
17474 invisible_parent_tests();
17475 cleanup_tests();
17476 }
17477
17478 START_TEST(msg_paint)
17479 {
17480 init_tests();
17481 test_scrollwindowex();
17482 test_paint_messages();
17483 #ifdef __REACTOS__
17484 if (!winetest_interactive &&
17485 !strcmp(winetest_platform, "windows"))
17486 {
17487 skip("ROSTESTS-185: Skipping user32_winetest:msg_paint test_paintingloop because it hangs on WHS-Testbot. Set winetest_interactive to run it anyway.\n");
17488 }
17489 else
17490 #endif
17491 test_paintingloop();
17492 cleanup_tests();
17493 }
17494
17495 START_TEST(msg_input)
17496 {
17497 init_tests();
17498 test_accelerators();
17499 if (!pTrackMouseEvent)
17500 win_skip("TrackMouseEvent is not available\n");
17501 else
17502 test_TrackMouseEvent();
17503
17504 test_keyflags();
17505 test_hotkey();
17506 cleanup_tests();
17507 }
17508
17509 START_TEST(msg_timer)
17510 {
17511 init_tests();
17512 test_timers();
17513 test_timers_no_wnd();
17514 test_timers_exceptions();
17515 cleanup_tests();
17516 }
17517
17518 typedef BOOL (WINAPI *IS_WINEVENT_HOOK_INSTALLED)(DWORD);
17519
17520 START_TEST(msg_hook)
17521 {
17522 // HMODULE user32 = GetModuleHandleA("user32.dll");
17523 // IS_WINEVENT_HOOK_INSTALLED pIsWinEventHookInstalled = (IS_WINEVENT_HOOK_INSTALLED)GetProcAddress(user32, "IsWinEventHookInstalled");
17524 BOOL (WINAPI *pIsWinEventHookInstalled)(DWORD)= 0;/*GetProcAddress(user32, "IsWinEventHookInstalled");*/
17525
17526 init_tests();
17527
17528 if (pSetWinEventHook)
17529 {
17530 hEvent_hook = pSetWinEventHook(EVENT_MIN, EVENT_MAX,
17531 GetModuleHandleA(0), win_event_proc,
17532 0, GetCurrentThreadId(),
17533 WINEVENT_INCONTEXT);
17534 if (pIsWinEventHookInstalled && hEvent_hook)
17535 {
17536 UINT event;
17537 for (event = EVENT_MIN; event <= EVENT_MAX; event++)
17538 ok(pIsWinEventHookInstalled(event), "IsWinEventHookInstalled(%u) failed\n", event);
17539 }
17540 }
17541 if (!hEvent_hook) win_skip( "no win event hook support\n" );
17542
17543 test_winevents();
17544
17545 /* Fix message sequences before removing 4 lines below */
17546 if (pUnhookWinEvent && hEvent_hook)
17547 {
17548 BOOL ret;
17549 ret = pUnhookWinEvent(hEvent_hook);
17550 ok( ret, "UnhookWinEvent error %d\n", GetLastError());
17551 pUnhookWinEvent = 0;
17552 }
17553 hEvent_hook = 0;
17554 if (hCBT_hook)
17555 {
17556 test_set_hook();
17557 test_recursive_hook();
17558 }
17559 cleanup_tests();
17560 }
17561
17562 START_TEST(msg_menu)
17563 {
17564 init_tests();
17565 test_sys_menu();
17566 test_menu_messages();
17567 test_TrackPopupMenu();
17568 test_TrackPopupMenuEmpty();
17569 cleanup_tests();
17570 }
17571
17572 START_TEST(msg_mdi)
17573 {
17574 init_tests();
17575 test_mdi_messages();
17576 cleanup_tests();
17577 }
17578
17579 START_TEST(msg_controls)
17580 {
17581 init_tests();
17582 test_button_messages();
17583 test_autoradio_BM_CLICK();
17584 test_autoradio_kbd_move();
17585 test_static_messages();
17586 test_listbox_messages();
17587 test_combobox_messages();
17588 test_edit_messages();
17589 cleanup_tests();
17590 }
17591
17592 START_TEST(msg_layered_window)
17593 {
17594 init_tests();
17595 test_layered_window();
17596 cleanup_tests();
17597 }
17598
17599 START_TEST(msg_dialog)
17600 {
17601 init_tests();
17602 test_dialog_messages();
17603 test_EndDialog();
17604 cleanup_tests();
17605 }
17606
17607 START_TEST(msg_clipboard)
17608 {
17609 init_tests();
17610 test_clipboard_viewers();
17611 cleanup_tests();
17612 }