user32/tests: Add some tests for WindowFromDC and destroyed windows.
[wine.git] / dlls / user32 / tests / dce.c
blob25b01530dc5a8e057bcf5ddff69a7601186a99f9
1 /*
2 * Unit tests for DCE support
4 * Copyright 2005 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdlib.h>
22 #include <stdarg.h>
23 #include <stdio.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
30 #include "wine/test.h"
32 #ifndef DCX_USESTYLE
33 #define DCX_USESTYLE 0x00010000
34 #endif
36 static HWND hwnd_cache, hwnd_owndc, hwnd_classdc, hwnd_classdc2, hwnd_parent, hwnd_parentdc;
38 /* test behavior of DC attributes with various GetDC/ReleaseDC combinations */
39 static void test_dc_attributes(void)
41 HDC hdc, old_hdc;
42 HDC hdcs[20];
43 INT i, rop, def_rop;
44 BOOL found_dc;
46 /* test cache DC */
48 hdc = GetDC( hwnd_cache );
49 def_rop = GetROP2( hdc );
51 SetROP2( hdc, R2_WHITE );
52 rop = GetROP2( hdc );
53 ok( rop == R2_WHITE, "wrong ROP2 %d\n", rop );
55 ok( WindowFromDC( hdc ) == hwnd_cache, "wrong window\n" );
56 ReleaseDC( hwnd_cache, hdc );
57 ok( WindowFromDC( hdc ) == 0, "wrong window\n" );
58 hdc = GetDC( hwnd_cache );
59 rop = GetROP2( hdc );
60 ok( rop == def_rop, "wrong ROP2 %d after release\n", rop );
61 SetROP2( hdc, R2_WHITE );
62 ok( WindowFromDC( hdc ) == hwnd_cache, "wrong window\n" );
63 ReleaseDC( hwnd_cache, hdc );
64 old_hdc = hdc;
66 found_dc = FALSE;
67 for (i = 0; i < 20; i++)
69 hdc = hdcs[i] = GetDCEx( hwnd_cache, 0, DCX_USESTYLE | DCX_NORESETATTRS );
70 if (!hdc) break;
71 rop = GetROP2( hdc );
72 ok( rop == def_rop, "wrong ROP2 %d after release %p/%p\n", rop, old_hdc, hdc );
73 if (hdc == old_hdc)
75 found_dc = TRUE;
76 SetROP2( hdc, R2_WHITE );
79 if (!found_dc)
81 trace( "hdc %p not found in cache using %p\n", old_hdc, hdcs[0] );
82 old_hdc = hdcs[0];
83 SetROP2( old_hdc, R2_WHITE );
85 while (i > 0) ReleaseDC( hwnd_cache, hdcs[--i] );
87 for (i = 0; i < 20; i++)
89 hdc = hdcs[i] = GetDCEx( hwnd_cache, 0, DCX_USESTYLE | DCX_NORESETATTRS );
90 if (!hdc) break;
91 rop = GetROP2( hdc );
92 if (hdc == old_hdc)
93 ok( rop == R2_WHITE || broken( rop == def_rop), /* win9x doesn't support DCX_NORESETATTRS */
94 "wrong ROP2 %d after release %p/%p\n", rop, old_hdc, hdc );
95 else
96 ok( rop == def_rop, "wrong ROP2 %d after release %p/%p\n", rop, old_hdc, hdc );
98 while (i > 0) ReleaseDC( hwnd_cache, hdcs[--i] );
100 for (i = 0; i < 20; i++)
102 hdc = hdcs[i] = GetDCEx( hwnd_cache, 0, DCX_USESTYLE );
103 if (!hdc) break;
104 rop = GetROP2( hdc );
105 if (hdc == old_hdc)
107 ok( rop == R2_WHITE || broken( rop == def_rop),
108 "wrong ROP2 %d after release %p/%p\n", rop, old_hdc, hdc );
109 SetROP2( old_hdc, def_rop );
111 else
112 ok( rop == def_rop, "wrong ROP2 %d after release %p/%p\n", rop, old_hdc, hdc );
114 while (i > 0) ReleaseDC( hwnd_cache, hdcs[--i] );
116 /* Released cache DCs are 'disabled' */
117 rop = SetROP2( old_hdc, R2_BLACK );
118 ok( rop == 0, "got %d\n", rop );
119 rop = GetROP2( old_hdc );
120 ok( rop == 0, "got %d\n", rop );
121 ok( WindowFromDC( old_hdc ) == 0, "wrong window\n" );
123 /* test own DC */
125 hdc = GetDC( hwnd_owndc );
126 SetROP2( hdc, R2_WHITE );
127 rop = GetROP2( hdc );
128 ok( rop == R2_WHITE, "wrong ROP2 %d\n", rop );
130 old_hdc = hdc;
131 ok( WindowFromDC( hdc ) == hwnd_owndc, "wrong window\n" );
132 ReleaseDC( hwnd_owndc, hdc );
133 ok( WindowFromDC( hdc ) == hwnd_owndc, "wrong window\n" );
134 hdc = GetDC( hwnd_owndc );
135 ok( old_hdc == hdc, "didn't get same DC %p/%p\n", old_hdc, hdc );
136 rop = GetROP2( hdc );
137 ok( rop == R2_WHITE, "wrong ROP2 %d after release\n", rop );
138 ok( WindowFromDC( hdc ) == hwnd_owndc, "wrong window\n" );
139 ReleaseDC( hwnd_owndc, hdc );
140 rop = GetROP2( hdc );
141 ok( rop == R2_WHITE, "wrong ROP2 %d after second release\n", rop );
143 /* test class DC */
145 hdc = GetDC( hwnd_classdc );
146 SetROP2( hdc, R2_WHITE );
147 rop = GetROP2( hdc );
148 ok( rop == R2_WHITE, "wrong ROP2 %d\n", rop );
150 old_hdc = hdc;
151 ok( WindowFromDC( hdc ) == hwnd_classdc, "wrong window\n" );
152 ReleaseDC( hwnd_classdc, hdc );
153 ok( WindowFromDC( hdc ) == hwnd_classdc, "wrong window\n" );
154 hdc = GetDC( hwnd_classdc );
155 ok( old_hdc == hdc, "didn't get same DC %p/%p\n", old_hdc, hdc );
156 rop = GetROP2( hdc );
157 ok( rop == R2_WHITE, "wrong ROP2 %d after release\n", rop );
158 ok( WindowFromDC( hdc ) == hwnd_classdc, "wrong window\n" );
159 ReleaseDC( hwnd_classdc, hdc );
160 rop = GetROP2( hdc );
161 ok( rop == R2_WHITE, "wrong ROP2 %d after second release\n", rop );
163 /* test class DC with 2 windows */
165 old_hdc = GetDC( hwnd_classdc );
166 SetROP2( old_hdc, R2_BLACK );
167 ok( WindowFromDC( old_hdc ) == hwnd_classdc, "wrong window\n" );
168 hdc = GetDC( hwnd_classdc2 );
169 ok( old_hdc == hdc, "didn't get same DC %p/%p\n", old_hdc, hdc );
170 rop = GetROP2( hdc );
171 ok( rop == R2_BLACK, "wrong ROP2 %d for other window\n", rop );
172 ok( WindowFromDC( hdc ) == hwnd_classdc2, "wrong window\n" );
173 ReleaseDC( hwnd_classdc, old_hdc );
174 ReleaseDC( hwnd_classdc, hdc );
175 ok( WindowFromDC( hdc ) == hwnd_classdc2, "wrong window\n" );
176 rop = GetROP2( hdc );
177 ok( rop == R2_BLACK, "wrong ROP2 %d after release\n", rop );
181 /* test behavior with various invalid parameters */
182 static void test_parameters(void)
184 HDC hdc;
186 hdc = GetDC( hwnd_cache );
187 ok( ReleaseDC( hwnd_owndc, hdc ), "ReleaseDC with wrong window should succeed\n" );
189 hdc = GetDC( hwnd_cache );
190 ok( !ReleaseDC( hwnd_cache, 0 ), "ReleaseDC with wrong HDC should fail\n" );
191 ok( ReleaseDC( hwnd_cache, hdc ), "correct ReleaseDC should succeed\n" );
192 ok( !ReleaseDC( hwnd_cache, hdc ), "second ReleaseDC should fail\n" );
194 hdc = GetDC( hwnd_owndc );
195 ok( ReleaseDC( hwnd_cache, hdc ), "ReleaseDC with wrong window should succeed\n" );
196 hdc = GetDC( hwnd_owndc );
197 ok( ReleaseDC( hwnd_owndc, hdc ), "correct ReleaseDC should succeed\n" );
198 ok( ReleaseDC( hwnd_owndc, hdc ), "second ReleaseDC should succeed\n" );
200 hdc = GetDC( hwnd_classdc );
201 ok( ReleaseDC( hwnd_cache, hdc ), "ReleaseDC with wrong window should succeed\n" );
202 hdc = GetDC( hwnd_classdc );
203 ok( ReleaseDC( hwnd_classdc, hdc ), "correct ReleaseDC should succeed\n" );
204 ok( ReleaseDC( hwnd_classdc, hdc ), "second ReleaseDC should succeed\n" );
208 static void test_dc_visrgn(void)
210 HDC old_hdc, hdc;
211 HRGN hrgn, hrgn2;
212 RECT rect, parent_rect;
214 /* cache DC */
216 SetRect( &rect, 10, 10, 20, 20 );
217 MapWindowPoints( hwnd_cache, 0, (POINT *)&rect, 2 );
218 hrgn = CreateRectRgnIndirect( &rect );
219 hdc = GetDCEx( hwnd_cache, hrgn, DCX_INTERSECTRGN | DCX_USESTYLE );
220 SetRectEmpty( &rect );
221 GetClipBox( hdc, &rect );
222 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
223 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
224 ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
225 ReleaseDC( hwnd_cache, hdc );
226 ok( GetRgnBox( hrgn, &rect ) == ERROR, "region must no longer be valid\n" );
228 /* cache DC with NORESETATTRS */
230 SetRect( &rect, 10, 10, 20, 20 );
231 MapWindowPoints( hwnd_cache, 0, (POINT *)&rect, 2 );
232 hrgn = CreateRectRgnIndirect( &rect );
233 hdc = GetDCEx( hwnd_cache, hrgn, DCX_INTERSECTRGN | DCX_USESTYLE | DCX_NORESETATTRS );
234 SetRectEmpty( &rect );
235 GetClipBox( hdc, &rect );
236 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
237 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
238 ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
239 ReleaseDC( hwnd_cache, hdc );
240 ok( GetRgnBox( hrgn, &rect ) == ERROR, "region must no longer be valid\n" );
241 hdc = GetDCEx( hwnd_cache, 0, DCX_USESTYLE | DCX_NORESETATTRS );
242 SetRectEmpty( &rect );
243 GetClipBox( hdc, &rect );
244 ok( !(rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20),
245 "clip box should have been reset %s\n", wine_dbgstr_rect( &rect ));
246 ReleaseDC( hwnd_cache, hdc );
248 /* window DC */
250 SetRect( &rect, 10, 10, 20, 20 );
251 MapWindowPoints( hwnd_owndc, 0, (POINT *)&rect, 2 );
252 hrgn = CreateRectRgnIndirect( &rect );
253 hdc = GetDCEx( hwnd_owndc, hrgn, DCX_INTERSECTRGN | DCX_USESTYLE );
254 SetRectEmpty( &rect );
255 GetClipBox( hdc, &rect );
256 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
257 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
258 ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
259 ReleaseDC( hwnd_owndc, hdc );
260 ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
261 SetRectEmpty( &rect );
262 GetClipBox( hdc, &rect );
263 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
264 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
265 hdc = GetDCEx( hwnd_owndc, 0, DCX_USESTYLE );
266 SetRectEmpty( &rect );
267 GetClipBox( hdc, &rect );
268 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
269 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
270 ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
271 ReleaseDC( hwnd_owndc, hdc );
272 ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
274 SetRect( &rect, 20, 20, 30, 30 );
275 MapWindowPoints( hwnd_owndc, 0, (POINT *)&rect, 2 );
276 hrgn2 = CreateRectRgnIndirect( &rect );
277 hdc = GetDCEx( hwnd_owndc, hrgn2, DCX_INTERSECTRGN | DCX_USESTYLE );
278 ok( GetRgnBox( hrgn, &rect ) == ERROR, "region must no longer be valid\n" );
279 SetRectEmpty( &rect );
280 GetClipBox( hdc, &rect );
281 ok( rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30,
282 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
283 ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
284 ReleaseDC( hwnd_owndc, hdc );
285 ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
286 hdc = GetDCEx( hwnd_owndc, 0, DCX_EXCLUDERGN | DCX_USESTYLE );
287 ok( GetRgnBox( hrgn2, &rect ) == ERROR, "region must no longer be valid\n" );
288 SetRectEmpty( &rect );
289 GetClipBox( hdc, &rect );
290 ok( !(rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30),
291 "clip box should have been reset %s\n", wine_dbgstr_rect( &rect ));
292 ReleaseDC( hwnd_owndc, hdc );
294 /* class DC */
296 SetRect( &rect, 10, 10, 20, 20 );
297 MapWindowPoints( hwnd_classdc, 0, (POINT *)&rect, 2 );
298 hrgn = CreateRectRgnIndirect( &rect );
299 hdc = GetDCEx( hwnd_classdc, hrgn, DCX_INTERSECTRGN | DCX_USESTYLE );
300 SetRectEmpty( &rect );
301 GetClipBox( hdc, &rect );
302 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
303 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
304 ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
305 ReleaseDC( hwnd_classdc, hdc );
306 ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
307 SetRectEmpty( &rect );
308 GetClipBox( hdc, &rect );
309 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
310 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
312 hdc = GetDCEx( hwnd_classdc, 0, DCX_USESTYLE );
313 SetRectEmpty( &rect );
314 GetClipBox( hdc, &rect );
315 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
316 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
317 ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
318 ReleaseDC( hwnd_classdc, hdc );
319 ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
321 SetRect( &rect, 20, 20, 30, 30 );
322 MapWindowPoints( hwnd_classdc, 0, (POINT *)&rect, 2 );
323 hrgn2 = CreateRectRgnIndirect( &rect );
324 hdc = GetDCEx( hwnd_classdc, hrgn2, DCX_INTERSECTRGN | DCX_USESTYLE );
325 ok( GetRgnBox( hrgn, &rect ) == ERROR, "region must no longer be valid\n" );
326 SetRectEmpty( &rect );
327 GetClipBox( hdc, &rect );
328 ok( rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30,
329 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
330 ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
332 old_hdc = hdc;
333 hdc = GetDCEx( hwnd_classdc2, 0, DCX_USESTYLE );
334 ok( old_hdc == hdc, "did not get the same hdc %p/%p\n", old_hdc, hdc );
335 ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
336 SetRectEmpty( &rect );
337 GetClipBox( hdc, &rect );
338 ok( !(rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30),
339 "clip box should have been reset %s\n", wine_dbgstr_rect( &rect ));
340 ReleaseDC( hwnd_classdc2, hdc );
341 ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
342 hdc = GetDCEx( hwnd_classdc2, 0, DCX_EXCLUDERGN | DCX_USESTYLE );
343 ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
344 ok( !(rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30),
345 "clip box must have been reset %s\n", wine_dbgstr_rect( &rect ));
346 ReleaseDC( hwnd_classdc2, hdc );
348 /* parent DC */
349 hdc = GetDC( hwnd_parentdc );
350 GetClipBox( hdc, &rect );
351 ReleaseDC( hwnd_parentdc, hdc );
353 hdc = GetDC( hwnd_parent );
354 GetClipBox( hdc, &parent_rect );
355 ReleaseDC( hwnd_parent, hdc );
357 ok( EqualRect( &rect, &parent_rect ), "rect = %s, expected %s\n", wine_dbgstr_rect( &rect ),
358 wine_dbgstr_rect( &parent_rect ));
362 /* test various BeginPaint/EndPaint behaviors */
363 static void test_begin_paint(void)
365 HDC old_hdc, hdc;
366 RECT rect, parent_rect;
367 PAINTSTRUCT ps;
368 COLORREF cr;
370 /* cache DC */
372 /* clear update region */
373 RedrawWindow( hwnd_cache, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
374 SetRect( &rect, 10, 10, 20, 20 );
375 RedrawWindow( hwnd_cache, &rect, 0, RDW_INVALIDATE );
376 hdc = BeginPaint( hwnd_cache, &ps );
377 SetRectEmpty( &rect );
378 GetClipBox( hdc, &rect );
379 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
380 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
381 EndPaint( hwnd_cache, &ps );
383 /* window DC */
385 RedrawWindow( hwnd_owndc, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
386 SetRect( &rect, 10, 10, 20, 20 );
387 RedrawWindow( hwnd_owndc, &rect, 0, RDW_INVALIDATE );
388 hdc = BeginPaint( hwnd_owndc, &ps );
389 SetRectEmpty( &rect );
390 GetClipBox( hdc, &rect );
391 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
392 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
393 ReleaseDC( hwnd_owndc, hdc );
394 SetRectEmpty( &rect );
395 GetClipBox( hdc, &rect );
396 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
397 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
398 ok( GetDC( hwnd_owndc ) == hdc, "got different hdc\n" );
399 SetRectEmpty( &rect );
400 GetClipBox( hdc, &rect );
401 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
402 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
403 EndPaint( hwnd_owndc, &ps );
404 SetRectEmpty( &rect );
405 GetClipBox( hdc, &rect );
406 ok( !(rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20),
407 "clip box should have been reset %s\n", wine_dbgstr_rect( &rect ));
408 RedrawWindow( hwnd_owndc, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
409 SetRect( &rect, 10, 10, 20, 20 );
410 RedrawWindow( hwnd_owndc, &rect, 0, RDW_INVALIDATE|RDW_ERASE );
411 ok( GetDC( hwnd_owndc ) == hdc, "got different hdc\n" );
412 SetRectEmpty( &rect );
413 GetClipBox( hdc, &rect );
414 ok( !(rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20),
415 "clip box should be the whole window %s\n", wine_dbgstr_rect( &rect ));
416 RedrawWindow( hwnd_owndc, NULL, 0, RDW_ERASENOW );
417 SetRectEmpty( &rect );
418 GetClipBox( hdc, &rect );
419 ok( !(rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20),
420 "clip box should still be the whole window %s\n", wine_dbgstr_rect( &rect ));
422 /* class DC */
424 RedrawWindow( hwnd_classdc, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
425 SetRect( &rect, 10, 10, 20, 20 );
426 RedrawWindow( hwnd_classdc, &rect, 0, RDW_INVALIDATE );
427 hdc = BeginPaint( hwnd_classdc, &ps );
428 SetRectEmpty( &rect );
429 GetClipBox( hdc, &rect );
430 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
431 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
433 old_hdc = hdc;
434 hdc = GetDC( hwnd_classdc2 );
435 ok( old_hdc == hdc, "did not get the same hdc %p/%p\n", old_hdc, hdc );
436 SetRectEmpty( &rect );
437 GetClipBox( hdc, &rect );
438 ok( !(rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20),
439 "clip box should have been reset %s\n", wine_dbgstr_rect( &rect ));
440 ReleaseDC( hwnd_classdc2, hdc );
441 EndPaint( hwnd_classdc, &ps );
443 /* parent DC */
444 RedrawWindow( hwnd_parent, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
445 RedrawWindow( hwnd_parentdc, NULL, 0, RDW_INVALIDATE );
446 hdc = BeginPaint( hwnd_parentdc, &ps );
447 GetClipBox( hdc, &rect );
448 cr = SetPixel( hdc, 10, 10, RGB(255, 0, 0) );
449 ok( cr != -1, "error drawing outside of window client area\n" );
450 EndPaint( hwnd_parentdc, &ps );
451 GetClientRect( hwnd_parent, &parent_rect );
453 ok( rect.left == parent_rect.left, "rect.left = %d, expected %d\n", rect.left, parent_rect.left );
454 ok( rect.top == parent_rect.top, "rect.top = %d, expected %d\n", rect.top, parent_rect.top );
455 todo_wine ok( rect.right == parent_rect.right, "rect.right = %d, expected %d\n", rect.right, parent_rect.right );
456 todo_wine ok( rect.bottom == parent_rect.bottom, "rect.bottom = %d, expected %d\n", rect.bottom, parent_rect.bottom );
458 hdc = GetDC( hwnd_parent );
459 todo_wine ok( GetPixel( hdc, 10, 10 ) == cr, "error drawing outside of window client area\n" );
460 ReleaseDC( hwnd_parent, hdc );
463 /* test ScrollWindow with window DCs */
464 static void test_scroll_window(void)
466 PAINTSTRUCT ps;
467 HDC hdc;
468 RECT clip, rect;
470 /* ScrollWindow uses the window DC, ScrollWindowEx doesn't */
472 UpdateWindow( hwnd_owndc );
473 SetRect( &clip, 25, 25, 50, 50 );
474 ScrollWindow( hwnd_owndc, -5, -10, NULL, &clip );
475 hdc = BeginPaint( hwnd_owndc, &ps );
476 SetRectEmpty( &rect );
477 GetClipBox( hdc, &rect );
478 ok( rect.left >= 25 && rect.top >= 25 && rect.right <= 50 && rect.bottom <= 50,
479 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
480 EndPaint( hwnd_owndc, &ps );
482 SetViewportExtEx( hdc, 2, 3, NULL );
483 SetViewportOrgEx( hdc, 30, 20, NULL );
485 ScrollWindow( hwnd_owndc, -5, -10, NULL, &clip );
486 hdc = BeginPaint( hwnd_owndc, &ps );
487 SetRectEmpty( &rect );
488 GetClipBox( hdc, &rect );
489 ok( rect.left >= 25 && rect.top >= 25 && rect.right <= 50 && rect.bottom <= 50,
490 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
491 EndPaint( hwnd_owndc, &ps );
493 ScrollWindowEx( hwnd_owndc, -5, -10, NULL, &clip, 0, NULL, SW_INVALIDATE | SW_ERASE );
494 hdc = BeginPaint( hwnd_owndc, &ps );
495 SetRectEmpty( &rect );
496 GetClipBox( hdc, &rect );
497 ok( rect.left >= -5 && rect.top >= 5 && rect.right <= 20 && rect.bottom <= 30,
498 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
499 EndPaint( hwnd_owndc, &ps );
501 SetViewportExtEx( hdc, 1, 1, NULL );
502 SetViewportOrgEx( hdc, 0, 0, NULL );
504 ScrollWindowEx( hwnd_owndc, -5, -10, NULL, &clip, 0, NULL, SW_INVALIDATE | SW_ERASE );
505 hdc = BeginPaint( hwnd_owndc, &ps );
506 SetRectEmpty( &rect );
507 GetClipBox( hdc, &rect );
508 ok( rect.left >= 25 && rect.top >= 25 && rect.right <= 50 && rect.bottom <= 50,
509 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
510 EndPaint( hwnd_owndc, &ps );
513 static void test_invisible_create(void)
515 HWND hwnd_owndc = CreateWindowA("owndc_class", NULL, WS_OVERLAPPED,
516 0, 200, 100, 100,
517 0, 0, GetModuleHandleA(0), NULL );
518 HDC dc1, dc2;
520 dc1 = GetDC(hwnd_owndc);
521 dc2 = GetDC(hwnd_owndc);
523 ok(dc1 == dc2, "expected owndc dcs to match\n");
525 ReleaseDC(hwnd_owndc, dc2);
526 ReleaseDC(hwnd_owndc, dc1);
527 DestroyWindow(hwnd_owndc);
530 static void test_dc_layout(void)
532 DWORD (WINAPI *pSetLayout)(HDC hdc, DWORD layout);
533 DWORD (WINAPI *pGetLayout)(HDC hdc);
534 HWND hwnd_cache_rtl, hwnd_owndc_rtl, hwnd_classdc_rtl, hwnd_classdc2_rtl;
535 HDC hdc;
536 DWORD layout;
537 HMODULE mod = GetModuleHandleA("gdi32.dll");
539 pGetLayout = (void *)GetProcAddress( mod, "GetLayout" );
540 pSetLayout = (void *)GetProcAddress( mod, "SetLayout" );
541 if (!pGetLayout || !pSetLayout)
543 win_skip( "Don't have SetLayout\n" );
544 return;
547 hdc = GetDC( hwnd_cache );
548 pSetLayout( hdc, LAYOUT_RTL );
549 layout = pGetLayout( hdc );
550 ReleaseDC( hwnd_cache, hdc );
551 if (!layout)
553 win_skip( "SetLayout not supported\n" );
554 return;
557 hwnd_cache_rtl = CreateWindowExA(WS_EX_LAYOUTRTL, "cache_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
558 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL );
559 hwnd_owndc_rtl = CreateWindowExA(WS_EX_LAYOUTRTL, "owndc_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
560 0, 200, 100, 100, 0, 0, GetModuleHandleA(0), NULL );
561 hwnd_classdc_rtl = CreateWindowExA(WS_EX_LAYOUTRTL, "classdc_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
562 200, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL );
563 hwnd_classdc2_rtl = CreateWindowExA(WS_EX_LAYOUTRTL, "classdc_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
564 200, 200, 100, 100, 0, 0, GetModuleHandleA(0), NULL );
565 hdc = GetDC( hwnd_cache_rtl );
566 layout = pGetLayout( hdc );
568 ok( layout == LAYOUT_RTL, "wrong layout %x\n", layout );
569 pSetLayout( hdc, 0 );
570 ReleaseDC( hwnd_cache_rtl, hdc );
571 hdc = GetDC( hwnd_owndc_rtl );
572 layout = pGetLayout( hdc );
573 ok( layout == LAYOUT_RTL, "wrong layout %x\n", layout );
574 ReleaseDC( hwnd_cache_rtl, hdc );
576 hdc = GetDC( hwnd_cache );
577 layout = pGetLayout( hdc );
578 ok( layout == 0, "wrong layout %x\n", layout );
579 ReleaseDC( hwnd_cache, hdc );
581 hdc = GetDC( hwnd_owndc_rtl );
582 layout = pGetLayout( hdc );
583 ok( layout == LAYOUT_RTL, "wrong layout %x\n", layout );
584 pSetLayout( hdc, 0 );
585 ReleaseDC( hwnd_owndc_rtl, hdc );
586 hdc = GetDC( hwnd_owndc_rtl );
587 layout = pGetLayout( hdc );
588 ok( layout == LAYOUT_RTL, "wrong layout %x\n", layout );
589 ReleaseDC( hwnd_owndc_rtl, hdc );
591 hdc = GetDC( hwnd_classdc_rtl );
592 layout = pGetLayout( hdc );
593 ok( layout == LAYOUT_RTL, "wrong layout %x\n", layout );
594 pSetLayout( hdc, 0 );
595 ReleaseDC( hwnd_classdc_rtl, hdc );
596 hdc = GetDC( hwnd_classdc2_rtl );
597 layout = pGetLayout( hdc );
598 ok( layout == LAYOUT_RTL, "wrong layout %x\n", layout );
599 ReleaseDC( hwnd_classdc2_rtl, hdc );
600 hdc = GetDC( hwnd_classdc );
601 layout = pGetLayout( hdc );
602 ok( layout == LAYOUT_RTL, "wrong layout %x\n", layout );
603 ReleaseDC( hwnd_classdc_rtl, hdc );
605 DestroyWindow(hwnd_classdc2_rtl);
606 DestroyWindow(hwnd_classdc_rtl);
607 DestroyWindow(hwnd_owndc_rtl);
608 DestroyWindow(hwnd_cache_rtl);
611 static void test_destroyed_window(void)
613 HDC dc, old_dc;
614 HDC hdcs[30];
615 int i, rop;
617 dc = GetDC( hwnd_cache );
618 SetROP2( dc, R2_WHITE );
619 rop = GetROP2( dc );
620 ok( rop == R2_WHITE, "wrong ROP2 %d\n", rop );
621 ok( WindowFromDC( dc ) == hwnd_cache, "wrong window\n" );
622 old_dc = dc;
624 DestroyWindow( hwnd_cache );
625 rop = GetROP2( dc );
626 todo_wine ok( rop == 0, "wrong ROP2 %d\n", rop );
627 ok( WindowFromDC( dc ) == 0, "wrong window\n" );
628 ok( !ReleaseDC( hwnd_cache, dc ), "ReleaseDC succeeded\n" );
629 dc = GetDC( hwnd_cache );
630 ok( !dc, "Got a non-NULL DC (%p) for a destroyed window\n", dc );
632 for (i = 0; i < 30; i++)
634 dc = hdcs[i] = GetDCEx( hwnd_parent, 0, DCX_CACHE | DCX_USESTYLE );
635 if (dc == old_dc) break;
637 ok( i < 30, "DC for destroyed window not reused\n" );
638 while (i > 0) ReleaseDC( hwnd_parent, hdcs[--i] );
640 dc = GetDC( hwnd_classdc );
641 SetROP2( dc, R2_WHITE );
642 rop = GetROP2( dc );
643 ok( rop == R2_WHITE, "wrong ROP2 %d\n", rop );
644 ok( WindowFromDC( dc ) == hwnd_classdc, "wrong window\n" );
645 old_dc = dc;
647 dc = GetDC( hwnd_classdc2 );
648 ok( old_dc == dc, "wrong DC\n" );
649 rop = GetROP2( dc );
650 ok( rop == R2_WHITE, "wrong ROP2 %d\n", rop );
651 ok( WindowFromDC( dc ) == hwnd_classdc2, "wrong window\n" );
652 DestroyWindow( hwnd_classdc2 );
654 rop = GetROP2( dc );
655 ok( rop == R2_WHITE, "wrong ROP2 %d\n", rop );
656 ok( WindowFromDC( dc ) == 0, "wrong window\n" );
657 todo_wine ok( !ReleaseDC( hwnd_classdc2, dc ), "ReleaseDC succeeded\n" );
658 dc = GetDC( hwnd_classdc2 );
659 ok( !dc, "Got a non-NULL DC (%p) for a destroyed window\n", dc );
661 dc = GetDC( hwnd_classdc );
662 ok( dc != 0, "Got NULL DC\n" );
663 rop = GetROP2( dc );
664 todo_wine ok( rop == R2_WHITE, "wrong ROP2 %d\n", rop );
665 ok( WindowFromDC( dc ) == hwnd_classdc, "wrong window\n" );
666 DestroyWindow( hwnd_classdc );
668 rop = GetROP2( dc );
669 todo_wine ok( rop == R2_WHITE, "wrong ROP2 %d\n", rop );
670 ok( WindowFromDC( dc ) == 0, "wrong window\n" );
671 todo_wine ok( !ReleaseDC( hwnd_classdc, dc ), "ReleaseDC succeeded\n" );
672 dc = GetDC( hwnd_classdc );
673 ok( !dc, "Got a non-NULL DC (%p) for a destroyed window\n", dc );
675 dc = GetDC( hwnd_owndc );
676 ok( dc != 0, "Got NULL DC\n" );
677 rop = GetROP2( dc );
678 ok( rop == R2_WHITE, "wrong ROP2 %d\n", rop );
679 ok( WindowFromDC( dc ) == hwnd_owndc, "wrong window\n" );
680 DestroyWindow( hwnd_owndc );
682 rop = GetROP2( dc );
683 ok( rop == 0, "wrong ROP2 %d\n", rop );
684 ok( WindowFromDC( dc ) == 0, "wrong window\n" );
685 ok( !ReleaseDC( hwnd_owndc, dc ), "ReleaseDC succeeded\n" );
686 dc = GetDC( hwnd_owndc );
687 ok( !dc, "Got a non-NULL DC (%p) for a destroyed window\n", dc );
689 DestroyWindow( hwnd_parent );
692 START_TEST(dce)
694 WNDCLASSA cls;
696 cls.style = CS_DBLCLKS;
697 cls.lpfnWndProc = DefWindowProcA;
698 cls.cbClsExtra = 0;
699 cls.cbWndExtra = 0;
700 cls.hInstance = GetModuleHandleA(0);
701 cls.hIcon = 0;
702 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
703 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
704 cls.lpszMenuName = NULL;
705 cls.lpszClassName = "cache_class";
706 RegisterClassA(&cls);
707 cls.style = CS_DBLCLKS | CS_OWNDC;
708 cls.lpszClassName = "owndc_class";
709 RegisterClassA(&cls);
710 cls.style = CS_DBLCLKS | CS_CLASSDC;
711 cls.lpszClassName = "classdc_class";
712 RegisterClassA(&cls);
713 cls.style = CS_PARENTDC;
714 cls.lpszClassName = "parentdc_class";
715 RegisterClassA(&cls);
717 hwnd_cache = CreateWindowA("cache_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
718 0, 0, 100, 100,
719 0, 0, GetModuleHandleA(0), NULL );
720 hwnd_owndc = CreateWindowA("owndc_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
721 0, 200, 100, 100,
722 0, 0, GetModuleHandleA(0), NULL );
723 hwnd_classdc = CreateWindowA("classdc_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
724 200, 0, 100, 100,
725 0, 0, GetModuleHandleA(0), NULL );
726 hwnd_classdc2 = CreateWindowA("classdc_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
727 200, 200, 100, 100,
728 0, 0, GetModuleHandleA(0), NULL );
729 hwnd_parent = CreateWindowA("static", NULL, WS_OVERLAPPED | WS_VISIBLE,
730 400, 0, 100, 100, 0, 0, 0, NULL );
731 hwnd_parentdc = CreateWindowA("parentdc_class", NULL, WS_CHILD | WS_VISIBLE,
732 0, 0, 1, 1, hwnd_parent, 0, 0, NULL );
734 test_dc_attributes();
735 test_parameters();
736 test_dc_visrgn();
737 test_begin_paint();
738 test_scroll_window();
739 test_invisible_create();
740 test_dc_layout();
741 /* this should be last */
742 test_destroyed_window();