Merge branch 'ntfs_rebase'
[reactos.git] / modules / rostests / winetests / user32 / dce.c
1 /*
2 * Unit tests for DCE support
3 *
4 * Copyright 2005 Alexandre Julliard
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include "precomp.h"
22
23 #ifndef DCX_USESTYLE
24 #define DCX_USESTYLE 0x00010000
25 #endif
26
27 static HWND hwnd_cache, hwnd_owndc, hwnd_classdc, hwnd_classdc2, hwnd_parent, hwnd_parentdc;
28
29 /* test behavior of DC attributes with various GetDC/ReleaseDC combinations */
30 static void test_dc_attributes(void)
31 {
32 HDC hdc, old_hdc;
33 HDC hdcs[20];
34 INT i, rop, def_rop;
35 BOOL found_dc;
36
37 /* test cache DC */
38
39 hdc = GetDC( hwnd_cache );
40 def_rop = GetROP2( hdc );
41
42 SetROP2( hdc, R2_WHITE );
43 rop = GetROP2( hdc );
44 ok( rop == R2_WHITE, "wrong ROP2 %d\n", rop );
45
46 ReleaseDC( hwnd_cache, hdc );
47 hdc = GetDC( hwnd_cache );
48 rop = GetROP2( hdc );
49 ok( rop == def_rop, "wrong ROP2 %d after release\n", rop );
50 SetROP2( hdc, R2_WHITE );
51 ReleaseDC( hwnd_cache, hdc );
52 old_hdc = hdc;
53
54 found_dc = FALSE;
55 for (i = 0; i < 20; i++)
56 {
57 hdc = hdcs[i] = GetDCEx( hwnd_cache, 0, DCX_USESTYLE | DCX_NORESETATTRS );
58 if (!hdc) break;
59 rop = GetROP2( hdc );
60 ok( rop == def_rop, "wrong ROP2 %d after release %p/%p\n", rop, old_hdc, hdc );
61 if (hdc == old_hdc)
62 {
63 found_dc = TRUE;
64 SetROP2( hdc, R2_WHITE );
65 }
66 }
67 if (!found_dc)
68 {
69 trace( "hdc %p not found in cache using %p\n", old_hdc, hdcs[0] );
70 old_hdc = hdcs[0];
71 SetROP2( old_hdc, R2_WHITE );
72 }
73 while (i > 0) ReleaseDC( hwnd_cache, hdcs[--i] );
74
75 for (i = 0; i < 20; i++)
76 {
77 hdc = hdcs[i] = GetDCEx( hwnd_cache, 0, DCX_USESTYLE | DCX_NORESETATTRS );
78 if (!hdc) break;
79 rop = GetROP2( hdc );
80 if (hdc == old_hdc)
81 ok( rop == R2_WHITE || broken( rop == def_rop), /* win9x doesn't support DCX_NORESETATTRS */
82 "wrong ROP2 %d after release %p/%p\n", rop, old_hdc, hdc );
83 else
84 ok( rop == def_rop, "wrong ROP2 %d after release %p/%p\n", rop, old_hdc, hdc );
85 }
86 while (i > 0) ReleaseDC( hwnd_cache, hdcs[--i] );
87
88 for (i = 0; i < 20; i++)
89 {
90 hdc = hdcs[i] = GetDCEx( hwnd_cache, 0, DCX_USESTYLE );
91 if (!hdc) break;
92 rop = GetROP2( hdc );
93 if (hdc == old_hdc)
94 {
95 ok( rop == R2_WHITE || broken( rop == def_rop),
96 "wrong ROP2 %d after release %p/%p\n", rop, old_hdc, hdc );
97 SetROP2( old_hdc, def_rop );
98 }
99 else
100 ok( rop == def_rop, "wrong ROP2 %d after release %p/%p\n", rop, old_hdc, hdc );
101 }
102 while (i > 0) ReleaseDC( hwnd_cache, hdcs[--i] );
103
104 /* Released cache DCs are 'disabled' */
105 rop = SetROP2( old_hdc, R2_BLACK );
106 ok( rop == 0, "got %d\n", rop );
107 rop = GetROP2( old_hdc );
108 ok( rop == 0, "got %d\n", rop );
109
110 /* test own DC */
111
112 hdc = GetDC( hwnd_owndc );
113 SetROP2( hdc, R2_WHITE );
114 rop = GetROP2( hdc );
115 ok( rop == R2_WHITE, "wrong ROP2 %d\n", rop );
116
117 old_hdc = hdc;
118 ReleaseDC( hwnd_owndc, hdc );
119 hdc = GetDC( hwnd_owndc );
120 ok( old_hdc == hdc, "didn't get same DC %p/%p\n", old_hdc, hdc );
121 rop = GetROP2( hdc );
122 ok( rop == R2_WHITE, "wrong ROP2 %d after release\n", rop );
123 ReleaseDC( hwnd_owndc, hdc );
124 rop = GetROP2( hdc );
125 ok( rop == R2_WHITE, "wrong ROP2 %d after second release\n", rop );
126
127 /* test class DC */
128
129 hdc = GetDC( hwnd_classdc );
130 SetROP2( hdc, R2_WHITE );
131 rop = GetROP2( hdc );
132 ok( rop == R2_WHITE, "wrong ROP2 %d\n", rop );
133
134 old_hdc = hdc;
135 ReleaseDC( hwnd_classdc, hdc );
136 hdc = GetDC( hwnd_classdc );
137 ok( old_hdc == hdc, "didn't get same DC %p/%p\n", old_hdc, hdc );
138 rop = GetROP2( hdc );
139 ok( rop == R2_WHITE, "wrong ROP2 %d after release\n", rop );
140 ReleaseDC( hwnd_classdc, hdc );
141 rop = GetROP2( hdc );
142 ok( rop == R2_WHITE, "wrong ROP2 %d after second release\n", rop );
143
144 /* test class DC with 2 windows */
145
146 old_hdc = GetDC( hwnd_classdc );
147 SetROP2( old_hdc, R2_BLACK );
148 hdc = GetDC( hwnd_classdc2 );
149 ok( old_hdc == hdc, "didn't get same DC %p/%p\n", old_hdc, hdc );
150 rop = GetROP2( hdc );
151 ok( rop == R2_BLACK, "wrong ROP2 %d for other window\n", rop );
152 ReleaseDC( hwnd_classdc, old_hdc );
153 ReleaseDC( hwnd_classdc, hdc );
154 rop = GetROP2( hdc );
155 ok( rop == R2_BLACK, "wrong ROP2 %d after release\n", rop );
156 }
157
158
159 /* test behavior with various invalid parameters */
160 static void test_parameters(void)
161 {
162 HDC hdc;
163
164 hdc = GetDC( hwnd_cache );
165 ok( ReleaseDC( hwnd_owndc, hdc ), "ReleaseDC with wrong window should succeed\n" );
166
167 hdc = GetDC( hwnd_cache );
168 ok( !ReleaseDC( hwnd_cache, 0 ), "ReleaseDC with wrong HDC should fail\n" );
169 ok( ReleaseDC( hwnd_cache, hdc ), "correct ReleaseDC should succeed\n" );
170 ok( !ReleaseDC( hwnd_cache, hdc ), "second ReleaseDC should fail\n" );
171
172 hdc = GetDC( hwnd_owndc );
173 ok( ReleaseDC( hwnd_cache, hdc ), "ReleaseDC with wrong window should succeed\n" );
174 hdc = GetDC( hwnd_owndc );
175 ok( ReleaseDC( hwnd_owndc, hdc ), "correct ReleaseDC should succeed\n" );
176 ok( ReleaseDC( hwnd_owndc, hdc ), "second ReleaseDC should succeed\n" );
177
178 hdc = GetDC( hwnd_classdc );
179 ok( ReleaseDC( hwnd_cache, hdc ), "ReleaseDC with wrong window should succeed\n" );
180 hdc = GetDC( hwnd_classdc );
181 ok( ReleaseDC( hwnd_classdc, hdc ), "correct ReleaseDC should succeed\n" );
182 ok( ReleaseDC( hwnd_classdc, hdc ), "second ReleaseDC should succeed\n" );
183 }
184
185
186 static void test_dc_visrgn(void)
187 {
188 HDC old_hdc, hdc;
189 HRGN hrgn, hrgn2;
190 RECT rect, parent_rect;
191
192 /* cache DC */
193
194 SetRect( &rect, 10, 10, 20, 20 );
195 MapWindowPoints( hwnd_cache, 0, (POINT *)&rect, 2 );
196 hrgn = CreateRectRgnIndirect( &rect );
197 hdc = GetDCEx( hwnd_cache, hrgn, DCX_INTERSECTRGN | DCX_USESTYLE );
198 SetRectEmpty( &rect );
199 GetClipBox( hdc, &rect );
200 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
201 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
202 ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
203 ReleaseDC( hwnd_cache, hdc );
204 ok( GetRgnBox( hrgn, &rect ) == ERROR, "region must no longer be valid\n" );
205
206 /* cache DC with NORESETATTRS */
207
208 SetRect( &rect, 10, 10, 20, 20 );
209 MapWindowPoints( hwnd_cache, 0, (POINT *)&rect, 2 );
210 hrgn = CreateRectRgnIndirect( &rect );
211 hdc = GetDCEx( hwnd_cache, hrgn, DCX_INTERSECTRGN | DCX_USESTYLE | DCX_NORESETATTRS );
212 SetRectEmpty( &rect );
213 GetClipBox( hdc, &rect );
214 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
215 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
216 ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
217 ReleaseDC( hwnd_cache, hdc );
218 ok( GetRgnBox( hrgn, &rect ) == ERROR, "region must no longer be valid\n" );
219 hdc = GetDCEx( hwnd_cache, 0, DCX_USESTYLE | DCX_NORESETATTRS );
220 SetRectEmpty( &rect );
221 GetClipBox( hdc, &rect );
222 ok( !(rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20),
223 "clip box should have been reset %s\n", wine_dbgstr_rect( &rect ));
224 ReleaseDC( hwnd_cache, hdc );
225
226 /* window DC */
227
228 SetRect( &rect, 10, 10, 20, 20 );
229 MapWindowPoints( hwnd_owndc, 0, (POINT *)&rect, 2 );
230 hrgn = CreateRectRgnIndirect( &rect );
231 hdc = GetDCEx( hwnd_owndc, hrgn, DCX_INTERSECTRGN | DCX_USESTYLE );
232 SetRectEmpty( &rect );
233 GetClipBox( hdc, &rect );
234 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
235 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
236 ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
237 ReleaseDC( hwnd_owndc, hdc );
238 ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
239 SetRectEmpty( &rect );
240 GetClipBox( hdc, &rect );
241 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
242 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
243 hdc = GetDCEx( hwnd_owndc, 0, DCX_USESTYLE );
244 SetRectEmpty( &rect );
245 GetClipBox( hdc, &rect );
246 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
247 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
248 ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
249 ReleaseDC( hwnd_owndc, hdc );
250 ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
251
252 SetRect( &rect, 20, 20, 30, 30 );
253 MapWindowPoints( hwnd_owndc, 0, (POINT *)&rect, 2 );
254 hrgn2 = CreateRectRgnIndirect( &rect );
255 hdc = GetDCEx( hwnd_owndc, hrgn2, DCX_INTERSECTRGN | DCX_USESTYLE );
256 ok( GetRgnBox( hrgn, &rect ) == ERROR, "region must no longer be valid\n" );
257 SetRectEmpty( &rect );
258 GetClipBox( hdc, &rect );
259 ok( rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30,
260 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
261 ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
262 ReleaseDC( hwnd_owndc, hdc );
263 ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
264 hdc = GetDCEx( hwnd_owndc, 0, DCX_EXCLUDERGN | DCX_USESTYLE );
265 ok( GetRgnBox( hrgn2, &rect ) == ERROR, "region must no longer be valid\n" );
266 SetRectEmpty( &rect );
267 GetClipBox( hdc, &rect );
268 ok( !(rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30),
269 "clip box should have been reset %s\n", wine_dbgstr_rect( &rect ));
270 ReleaseDC( hwnd_owndc, hdc );
271
272 /* class DC */
273
274 SetRect( &rect, 10, 10, 20, 20 );
275 MapWindowPoints( hwnd_classdc, 0, (POINT *)&rect, 2 );
276 hrgn = CreateRectRgnIndirect( &rect );
277 hdc = GetDCEx( hwnd_classdc, hrgn, DCX_INTERSECTRGN | DCX_USESTYLE );
278 SetRectEmpty( &rect );
279 GetClipBox( hdc, &rect );
280 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
281 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
282 ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
283 ReleaseDC( hwnd_classdc, hdc );
284 ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
285 SetRectEmpty( &rect );
286 GetClipBox( hdc, &rect );
287 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
288 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
289
290 hdc = GetDCEx( hwnd_classdc, 0, DCX_USESTYLE );
291 SetRectEmpty( &rect );
292 GetClipBox( hdc, &rect );
293 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
294 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
295 ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
296 ReleaseDC( hwnd_classdc, hdc );
297 ok( GetRgnBox( hrgn, &rect ) != ERROR, "region must still be valid\n" );
298
299 SetRect( &rect, 20, 20, 30, 30 );
300 MapWindowPoints( hwnd_classdc, 0, (POINT *)&rect, 2 );
301 hrgn2 = CreateRectRgnIndirect( &rect );
302 hdc = GetDCEx( hwnd_classdc, hrgn2, DCX_INTERSECTRGN | DCX_USESTYLE );
303 ok( GetRgnBox( hrgn, &rect ) == ERROR, "region must no longer be valid\n" );
304 SetRectEmpty( &rect );
305 GetClipBox( hdc, &rect );
306 ok( rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30,
307 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
308 ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
309
310 old_hdc = hdc;
311 hdc = GetDCEx( hwnd_classdc2, 0, DCX_USESTYLE );
312 ok( old_hdc == hdc, "did not get the same hdc %p/%p\n", old_hdc, hdc );
313 ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
314 SetRectEmpty( &rect );
315 GetClipBox( hdc, &rect );
316 ok( !(rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30),
317 "clip box should have been reset %s\n", wine_dbgstr_rect( &rect ));
318 ReleaseDC( hwnd_classdc2, hdc );
319 ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
320 hdc = GetDCEx( hwnd_classdc2, 0, DCX_EXCLUDERGN | DCX_USESTYLE );
321 ok( GetRgnBox( hrgn2, &rect ) != ERROR, "region2 must still be valid\n" );
322 ok( !(rect.left >= 20 && rect.top >= 20 && rect.right <= 30 && rect.bottom <= 30),
323 "clip box must have been reset %s\n", wine_dbgstr_rect( &rect ));
324 ReleaseDC( hwnd_classdc2, hdc );
325
326 /* parent DC */
327 hdc = GetDC( hwnd_parentdc );
328 GetClipBox( hdc, &rect );
329 ReleaseDC( hwnd_parentdc, hdc );
330
331 hdc = GetDC( hwnd_parent );
332 GetClipBox( hdc, &parent_rect );
333 ReleaseDC( hwnd_parent, hdc );
334
335 ok( EqualRect( &rect, &parent_rect ), "rect = %s, expected %s\n", wine_dbgstr_rect( &rect ),
336 wine_dbgstr_rect( &parent_rect ));
337 }
338
339
340 /* test various BeginPaint/EndPaint behaviors */
341 static void test_begin_paint(void)
342 {
343 HDC old_hdc, hdc;
344 RECT rect, parent_rect;
345 PAINTSTRUCT ps;
346 COLORREF cr;
347
348 /* cache DC */
349
350 /* clear update region */
351 RedrawWindow( hwnd_cache, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
352 SetRect( &rect, 10, 10, 20, 20 );
353 RedrawWindow( hwnd_cache, &rect, 0, RDW_INVALIDATE );
354 hdc = BeginPaint( hwnd_cache, &ps );
355 SetRectEmpty( &rect );
356 GetClipBox( hdc, &rect );
357 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
358 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
359 EndPaint( hwnd_cache, &ps );
360
361 /* window DC */
362
363 RedrawWindow( hwnd_owndc, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
364 SetRect( &rect, 10, 10, 20, 20 );
365 RedrawWindow( hwnd_owndc, &rect, 0, RDW_INVALIDATE );
366 hdc = BeginPaint( hwnd_owndc, &ps );
367 SetRectEmpty( &rect );
368 GetClipBox( hdc, &rect );
369 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
370 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
371 ReleaseDC( hwnd_owndc, hdc );
372 SetRectEmpty( &rect );
373 GetClipBox( hdc, &rect );
374 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
375 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
376 ok( GetDC( hwnd_owndc ) == hdc, "got different hdc\n" );
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_owndc, &ps );
382 SetRectEmpty( &rect );
383 GetClipBox( hdc, &rect );
384 ok( !(rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20),
385 "clip box should have been reset %s\n", wine_dbgstr_rect( &rect ));
386 RedrawWindow( hwnd_owndc, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
387 SetRect( &rect, 10, 10, 20, 20 );
388 RedrawWindow( hwnd_owndc, &rect, 0, RDW_INVALIDATE|RDW_ERASE );
389 ok( GetDC( hwnd_owndc ) == hdc, "got different hdc\n" );
390 SetRectEmpty( &rect );
391 GetClipBox( hdc, &rect );
392 ok( !(rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20),
393 "clip box should be the whole window %s\n", wine_dbgstr_rect( &rect ));
394 RedrawWindow( hwnd_owndc, NULL, 0, RDW_ERASENOW );
395 SetRectEmpty( &rect );
396 GetClipBox( hdc, &rect );
397 ok( !(rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20),
398 "clip box should still be the whole window %s\n", wine_dbgstr_rect( &rect ));
399
400 /* class DC */
401
402 RedrawWindow( hwnd_classdc, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
403 SetRect( &rect, 10, 10, 20, 20 );
404 RedrawWindow( hwnd_classdc, &rect, 0, RDW_INVALIDATE );
405 hdc = BeginPaint( hwnd_classdc, &ps );
406 SetRectEmpty( &rect );
407 GetClipBox( hdc, &rect );
408 ok( rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20,
409 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
410
411 old_hdc = hdc;
412 hdc = GetDC( hwnd_classdc2 );
413 ok( old_hdc == hdc, "did not get the same hdc %p/%p\n", old_hdc, hdc );
414 SetRectEmpty( &rect );
415 GetClipBox( hdc, &rect );
416 ok( !(rect.left >= 10 && rect.top >= 10 && rect.right <= 20 && rect.bottom <= 20),
417 "clip box should have been reset %s\n", wine_dbgstr_rect( &rect ));
418 ReleaseDC( hwnd_classdc2, hdc );
419 EndPaint( hwnd_classdc, &ps );
420
421 /* parent DC */
422 RedrawWindow( hwnd_parent, NULL, 0, RDW_VALIDATE|RDW_NOFRAME|RDW_NOERASE );
423 RedrawWindow( hwnd_parentdc, NULL, 0, RDW_INVALIDATE );
424 hdc = BeginPaint( hwnd_parentdc, &ps );
425 GetClipBox( hdc, &rect );
426 cr = SetPixel( hdc, 10, 10, RGB(255, 0, 0) );
427 ok( cr != -1, "error drawing outside of window client area\n" );
428 EndPaint( hwnd_parentdc, &ps );
429 GetClientRect( hwnd_parent, &parent_rect );
430
431 ok( rect.left == parent_rect.left, "rect.left = %d, expected %d\n", rect.left, parent_rect.left );
432 ok( rect.top == parent_rect.top, "rect.top = %d, expected %d\n", rect.top, parent_rect.top );
433 todo_wine ok( rect.right == parent_rect.right, "rect.right = %d, expected %d\n", rect.right, parent_rect.right );
434 todo_wine ok( rect.bottom == parent_rect.bottom, "rect.bottom = %d, expected %d\n", rect.bottom, parent_rect.bottom );
435
436 hdc = GetDC( hwnd_parent );
437 todo_wine ok( GetPixel( hdc, 10, 10 ) == cr, "error drawing outside of window client area\n" );
438 ReleaseDC( hwnd_parent, hdc );
439 }
440
441 /* test ScrollWindow with window DCs */
442 static void test_scroll_window(void)
443 {
444 PAINTSTRUCT ps;
445 HDC hdc;
446 RECT clip, rect;
447
448 /* ScrollWindow uses the window DC, ScrollWindowEx doesn't */
449
450 UpdateWindow( hwnd_owndc );
451 SetRect( &clip, 25, 25, 50, 50 );
452 ScrollWindow( hwnd_owndc, -5, -10, NULL, &clip );
453 hdc = BeginPaint( hwnd_owndc, &ps );
454 SetRectEmpty( &rect );
455 GetClipBox( hdc, &rect );
456 ok( rect.left >= 25 && rect.top >= 25 && rect.right <= 50 && rect.bottom <= 50,
457 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
458 EndPaint( hwnd_owndc, &ps );
459
460 SetViewportExtEx( hdc, 2, 3, NULL );
461 SetViewportOrgEx( hdc, 30, 20, NULL );
462
463 ScrollWindow( hwnd_owndc, -5, -10, NULL, &clip );
464 hdc = BeginPaint( hwnd_owndc, &ps );
465 SetRectEmpty( &rect );
466 GetClipBox( hdc, &rect );
467 ok( rect.left >= 25 && rect.top >= 25 && rect.right <= 50 && rect.bottom <= 50,
468 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
469 EndPaint( hwnd_owndc, &ps );
470
471 ScrollWindowEx( hwnd_owndc, -5, -10, NULL, &clip, 0, NULL, SW_INVALIDATE | SW_ERASE );
472 hdc = BeginPaint( hwnd_owndc, &ps );
473 SetRectEmpty( &rect );
474 GetClipBox( hdc, &rect );
475 ok( rect.left >= -5 && rect.top >= 5 && rect.right <= 20 && rect.bottom <= 30,
476 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
477 EndPaint( hwnd_owndc, &ps );
478
479 SetViewportExtEx( hdc, 1, 1, NULL );
480 SetViewportOrgEx( hdc, 0, 0, NULL );
481
482 ScrollWindowEx( hwnd_owndc, -5, -10, NULL, &clip, 0, NULL, SW_INVALIDATE | SW_ERASE );
483 hdc = BeginPaint( hwnd_owndc, &ps );
484 SetRectEmpty( &rect );
485 GetClipBox( hdc, &rect );
486 ok( rect.left >= 25 && rect.top >= 25 && rect.right <= 50 && rect.bottom <= 50,
487 "invalid clip box %s\n", wine_dbgstr_rect( &rect ));
488 EndPaint( hwnd_owndc, &ps );
489 }
490
491 static void test_invisible_create(void)
492 {
493 HWND hwnd_owndc = CreateWindowA("owndc_class", NULL, WS_OVERLAPPED,
494 0, 200, 100, 100,
495 0, 0, GetModuleHandleA(0), NULL );
496 HDC dc1, dc2;
497
498 dc1 = GetDC(hwnd_owndc);
499 dc2 = GetDC(hwnd_owndc);
500
501 ok(dc1 == dc2, "expected owndc dcs to match\n");
502
503 ReleaseDC(hwnd_owndc, dc2);
504 ReleaseDC(hwnd_owndc, dc1);
505 DestroyWindow(hwnd_owndc);
506 }
507
508 static void test_dc_layout(void)
509 {
510 DWORD (WINAPI *pSetLayout)(HDC hdc, DWORD layout);
511 DWORD (WINAPI *pGetLayout)(HDC hdc);
512 HWND hwnd_cache_rtl, hwnd_owndc_rtl, hwnd_classdc_rtl, hwnd_classdc2_rtl;
513 HDC hdc;
514 DWORD layout;
515 HMODULE mod = GetModuleHandleA("gdi32.dll");
516
517 pGetLayout = (void *)GetProcAddress( mod, "GetLayout" );
518 pSetLayout = (void *)GetProcAddress( mod, "SetLayout" );
519 if (!pGetLayout || !pSetLayout)
520 {
521 win_skip( "Don't have SetLayout\n" );
522 return;
523 }
524
525 hdc = GetDC( hwnd_cache );
526 pSetLayout( hdc, LAYOUT_RTL );
527 layout = pGetLayout( hdc );
528 ReleaseDC( hwnd_cache, hdc );
529 if (!layout)
530 {
531 win_skip( "SetLayout not supported\n" );
532 return;
533 }
534
535 hwnd_cache_rtl = CreateWindowExA(WS_EX_LAYOUTRTL, "cache_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
536 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL );
537 hwnd_owndc_rtl = CreateWindowExA(WS_EX_LAYOUTRTL, "owndc_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
538 0, 200, 100, 100, 0, 0, GetModuleHandleA(0), NULL );
539 hwnd_classdc_rtl = CreateWindowExA(WS_EX_LAYOUTRTL, "classdc_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
540 200, 0, 100, 100, 0, 0, GetModuleHandleA(0), NULL );
541 hwnd_classdc2_rtl = CreateWindowExA(WS_EX_LAYOUTRTL, "classdc_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
542 200, 200, 100, 100, 0, 0, GetModuleHandleA(0), NULL );
543 hdc = GetDC( hwnd_cache_rtl );
544 layout = pGetLayout( hdc );
545
546 ok( layout == LAYOUT_RTL, "wrong layout %x\n", layout );
547 pSetLayout( hdc, 0 );
548 ReleaseDC( hwnd_cache_rtl, hdc );
549 hdc = GetDC( hwnd_owndc_rtl );
550 layout = pGetLayout( hdc );
551 ok( layout == LAYOUT_RTL, "wrong layout %x\n", layout );
552 ReleaseDC( hwnd_cache_rtl, hdc );
553
554 hdc = GetDC( hwnd_cache );
555 layout = pGetLayout( hdc );
556 ok( layout == 0, "wrong layout %x\n", layout );
557 ReleaseDC( hwnd_cache, hdc );
558
559 hdc = GetDC( hwnd_owndc_rtl );
560 layout = pGetLayout( hdc );
561 ok( layout == LAYOUT_RTL, "wrong layout %x\n", layout );
562 pSetLayout( hdc, 0 );
563 ReleaseDC( hwnd_owndc_rtl, hdc );
564 hdc = GetDC( hwnd_owndc_rtl );
565 layout = pGetLayout( hdc );
566 ok( layout == LAYOUT_RTL, "wrong layout %x\n", layout );
567 ReleaseDC( hwnd_owndc_rtl, hdc );
568
569 hdc = GetDC( hwnd_classdc_rtl );
570 layout = pGetLayout( hdc );
571 ok( layout == LAYOUT_RTL, "wrong layout %x\n", layout );
572 pSetLayout( hdc, 0 );
573 ReleaseDC( hwnd_classdc_rtl, hdc );
574 hdc = GetDC( hwnd_classdc2_rtl );
575 layout = pGetLayout( hdc );
576 ok( layout == LAYOUT_RTL, "wrong layout %x\n", layout );
577 ReleaseDC( hwnd_classdc2_rtl, hdc );
578 hdc = GetDC( hwnd_classdc );
579 layout = pGetLayout( hdc );
580 ok( layout == LAYOUT_RTL, "wrong layout %x\n", layout );
581 ReleaseDC( hwnd_classdc_rtl, hdc );
582
583 DestroyWindow(hwnd_classdc2_rtl);
584 DestroyWindow(hwnd_classdc_rtl);
585 DestroyWindow(hwnd_owndc_rtl);
586 DestroyWindow(hwnd_cache_rtl);
587 }
588
589 static void test_destroyed_window(void)
590 {
591 HDC dc;
592
593 dc = GetDCEx(hwnd_cache, 0, DCX_USESTYLE);
594 ok(!dc, "Got a non-NULL DC (%p) for a destroyed window.\n", dc);
595
596 dc = GetDCEx(hwnd_owndc, 0, DCX_USESTYLE);
597 ok(!dc, "Got a non-NULL DC (%p) for a destroyed window.\n", dc);
598
599 dc = GetDCEx(hwnd_classdc, 0, DCX_USESTYLE);
600 ok(!dc, "Got a non-NULL DC (%p) for a destroyed window.\n", dc);
601
602 dc = GetDCEx(hwnd_classdc2, 0, DCX_USESTYLE);
603 ok(!dc, "Got a non-NULL DC (%p) for a destroyed window.\n", dc);
604 }
605
606 START_TEST(dce)
607 {
608 WNDCLASSA cls;
609
610 cls.style = CS_DBLCLKS;
611 cls.lpfnWndProc = DefWindowProcA;
612 cls.cbClsExtra = 0;
613 cls.cbWndExtra = 0;
614 cls.hInstance = GetModuleHandleA(0);
615 cls.hIcon = 0;
616 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
617 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
618 cls.lpszMenuName = NULL;
619 cls.lpszClassName = "cache_class";
620 RegisterClassA(&cls);
621 cls.style = CS_DBLCLKS | CS_OWNDC;
622 cls.lpszClassName = "owndc_class";
623 RegisterClassA(&cls);
624 cls.style = CS_DBLCLKS | CS_CLASSDC;
625 cls.lpszClassName = "classdc_class";
626 RegisterClassA(&cls);
627 cls.style = CS_PARENTDC;
628 cls.lpszClassName = "parentdc_class";
629 RegisterClassA(&cls);
630
631 hwnd_cache = CreateWindowA("cache_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
632 0, 0, 100, 100,
633 0, 0, GetModuleHandleA(0), NULL );
634 hwnd_owndc = CreateWindowA("owndc_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
635 0, 200, 100, 100,
636 0, 0, GetModuleHandleA(0), NULL );
637 hwnd_classdc = CreateWindowA("classdc_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
638 200, 0, 100, 100,
639 0, 0, GetModuleHandleA(0), NULL );
640 hwnd_classdc2 = CreateWindowA("classdc_class", NULL, WS_OVERLAPPED | WS_VISIBLE,
641 200, 200, 100, 100,
642 0, 0, GetModuleHandleA(0), NULL );
643 hwnd_parent = CreateWindowA("static", NULL, WS_OVERLAPPED | WS_VISIBLE,
644 400, 0, 100, 100, 0, 0, 0, NULL );
645 hwnd_parentdc = CreateWindowA("parentdc_class", NULL, WS_CHILD | WS_VISIBLE,
646 0, 0, 1, 1, hwnd_parent, 0, 0, NULL );
647
648 test_dc_attributes();
649 test_parameters();
650 test_dc_visrgn();
651 test_begin_paint();
652 test_scroll_window();
653 test_invisible_create();
654 test_dc_layout();
655
656 DestroyWindow(hwnd_parent);
657 DestroyWindow(hwnd_classdc2);
658 DestroyWindow(hwnd_classdc);
659 DestroyWindow(hwnd_owndc);
660 DestroyWindow(hwnd_cache);
661
662 test_destroyed_window();
663 }