[KMTESTS:MM]
[reactos.git] / rostests / apitests / user32 / GetDCEx.c
1 /*
2 * PROJECT: ReactOS api tests
3 * LICENSE: GPL - See COPYING in the top level directory
4 * PURPOSE: Test for GetDCEx
5 * PROGRAMMERS: Timo Kreuzer
6 */
7
8 #include <stdio.h>
9 #include <wine/test.h>
10 #include <windows.h>
11
12 #define DCX_USESTYLE 0x00010000
13
14 void Test_GetDCEx_Params()
15 {
16
17 }
18
19 static
20 LRESULT
21 CALLBACK
22 WndProc(
23 _In_ HWND hwnd,
24 _In_ UINT uMsg,
25 _In_ WPARAM wParam,
26 _In_ LPARAM lParam)
27 {
28 return TRUE;
29 }
30
31 static
32 ATOM
33 RegisterClassHelper(
34 PSTR pszClassName,
35 UINT style,
36 WNDPROC pfnWndProc)
37 {
38 WNDCLASSA cls;
39
40 cls.style = style;
41 cls.lpfnWndProc = pfnWndProc;
42 cls.cbClsExtra = 0;
43 cls.cbWndExtra = 0;
44 cls.hInstance = GetModuleHandleA(0);
45 cls.hIcon = 0;
46 cls.hCursor = LoadCursorA(0, IDC_ARROW);
47 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
48 cls.lpszMenuName = NULL;
49 cls.lpszClassName = pszClassName;
50
51 return RegisterClassA(&cls);
52 }
53
54 static
55 HWND
56 CreateWindowHelper(
57 PSZ pszClassName,
58 PSZ pszTitle)
59 {
60 return CreateWindowA(pszClassName,
61 pszTitle,
62 WS_OVERLAPPEDWINDOW,
63 CW_USEDEFAULT,
64 CW_USEDEFAULT,
65 100,
66 100,
67 NULL,
68 NULL,
69 0,
70 NULL);
71 }
72
73 static
74 void
75 Test_GetDCEx_Cached()
76 {
77 static const PSTR pszClassName = "TestClass_Cached";
78 ATOM atomClass;
79 HWND hwnd;
80 HDC hdc1, hdc2;
81 HRGN hrgn;
82
83 atomClass = RegisterClassHelper(pszClassName, 0, WndProc);
84 ok(atomClass != 0, "Failed to register class\n");
85
86 hwnd = CreateWindowHelper(pszClassName, "Test Window1");
87 ok(hwnd != NULL, "Failed to create hwnd\n");
88
89 hdc1 = GetDCEx(hwnd, 0, 0);
90 ok(hdc1 == NULL, "GetDCEx should fail\n");
91 hrgn = CreateRectRgn(0, 0, 100, 100);
92 hdc1 = GetDCEx(hwnd, hrgn, 0);
93 ok(hdc1 == NULL, "GetDCEx should fail\n");
94
95 hdc1 = GetDCEx(hwnd, 0, DCX_WINDOW);
96 ok(hdc1 == NULL, "GetDCEx should fail\n");
97 hdc1 = GetDCEx(hwnd, hrgn, DCX_WINDOW);
98 ok(hdc1 == NULL, "GetDCEx should fail\n");
99
100 hdc1 = GetDCEx(hwnd, hrgn, DCX_INTERSECTRGN);
101 ok(hdc1 == NULL, "GetDCEx should fail\n");
102
103 hdc1 = GetDCEx(hwnd, hrgn, DCX_PARENTCLIP);
104 ok(hdc1 != NULL, "GetDCEx failed\n");
105 ReleaseDC(hwnd, hdc1);
106
107 hdc1 = GetDCEx(hwnd, hrgn, DCX_WINDOW | DCX_INTERSECTRGN | DCX_PARENTCLIP);
108 ok(hdc1 != NULL, "GetDCEx failed\n");
109 ReleaseDC(hwnd, hdc1);
110
111 hdc1 = GetDCEx(hwnd, 0, DCX_CACHE);
112 ok(hdc1 != NULL, "GetDCEx failed\n");
113 ReleaseDC(hwnd, hdc1);
114
115 hrgn = CreateRectRgn(0, 0, 100, 100);
116 hdc2 = GetDCEx(hwnd, hrgn, DCX_CACHE);
117 ok(hdc2 != NULL, "GetDCEx failed\n");
118 ReleaseDC(hwnd, hdc2);
119 ok(hdc2 == hdc1, "Expected the same DC\n");
120
121 hdc1 = GetDCEx(hwnd, 0, DCX_CACHE);
122 hdc2 = GetDCEx(hwnd, hrgn, DCX_CACHE);
123 ok(hdc1 != NULL, "GetDCEx failed\n");
124 ok(hdc2 != hdc1, "Expected a different DC\n");
125 ReleaseDC(hwnd, hdc1);
126 ReleaseDC(hwnd, hdc2);
127
128 hdc1 = GetDCEx(NULL, NULL, 0);
129 ok(hdc1 != NULL, "GetDCEx failed\n");
130 hdc2 = GetDCEx(NULL, NULL, 0);
131 ok(hdc2 != NULL, "GetDCEx failed\n");
132 ok(hdc2 != hdc1, "Expected a different DC\n");
133 ReleaseDC(hwnd, hdc1);
134 ReleaseDC(hwnd, hdc2);
135
136 ok(CombineRgn(hrgn, hrgn, hrgn, RGN_OR) == SIMPLEREGION, "region is not valid");
137
138 DestroyWindow(hwnd);
139 ok(UnregisterClass(pszClassName, GetModuleHandleA(0)) == TRUE,
140 "UnregisterClass failed");
141 }
142
143 static
144 void
145 Test_GetDCEx_CS_OWNDC()
146 {
147 static const PSTR pszClassName = "TestClass_CS_OWNDC";
148 ATOM atomClass;
149 HWND hwnd;
150 HDC hdc1, hdc2;
151 //HRGN hrgn;
152
153 atomClass = RegisterClassHelper(pszClassName, CS_OWNDC, WndProc);
154 ok(atomClass != 0, "Failed to register class\n");
155
156 hwnd = CreateWindowHelper(pszClassName, "Test Window1");
157 ok(hwnd != NULL, "Failed to create hwnd\n");
158
159 hdc1 = GetDCEx(hwnd, NULL, 0);
160 ok(hdc1 != NULL, "GetDCEx failed\n");
161 hdc2 = GetDCEx(hwnd, NULL, 0);
162 ok(hdc2 != NULL, "GetDCEx failed\n");
163 ok(hdc2 == hdc1, "Expected the same DC\n");
164 ok(ReleaseDC(hwnd, hdc1) == TRUE, "ReleaseDC failed\n");
165 ok(ReleaseDC(hwnd, hdc2) == TRUE, "ReleaseDC failed\n");
166
167 hdc2 = GetDCEx(hwnd, NULL, 0);
168 ok(hdc2 == hdc1, "Expected the same DC\n");
169 ok(ReleaseDC(hwnd, hdc2) == TRUE, "ReleaseDC failed\n");
170
171 hdc2 = GetDCEx(hwnd, NULL, DCX_CACHE);
172 ok(hdc2 != hdc1, "Expected a different DC\n");
173 ok(ReleaseDC(hwnd, hdc2) == TRUE, "ReleaseDC failed\n");
174
175 hdc2 = GetDCEx(hwnd, NULL, DCX_WINDOW);
176 ok(hdc2 == hdc1, "Expected the same DC\n");
177 ok(ReleaseDC(hwnd, hdc2) == TRUE, "ReleaseDC failed\n");
178
179 /* Try after resetting CS_OWNDC in the class */
180 ok(SetClassLongPtrA(hwnd, GCL_STYLE, 0) == CS_OWNDC, "class style wrong\n");
181 hdc2 = GetDCEx(hwnd, NULL, 0);
182 ok(hdc2 == hdc1, "Expected the same DC, got %p\n", hdc2);
183 ok(ReleaseDC(hwnd, hdc2) == TRUE, "ReleaseDC failed\n");
184
185 /* Try after setting CS_CLASSDC in the class */
186 ok(SetClassLongPtrA(hwnd, GCL_STYLE, CS_CLASSDC) == 0, "class style not set\n");
187 hdc2 = GetDCEx(hwnd, NULL, 0);
188 ok(hdc2 == hdc1, "Expected the same DC, got %p\n", hdc2);
189 ok(ReleaseDC(hwnd, hdc2) == TRUE, "ReleaseDC failed\n");
190
191 /* CS_OWNDC and CS_CLASSDC? Is that even legal? */
192 ok(SetClassLongPtrA(hwnd, GCL_STYLE, (CS_OWNDC | CS_CLASSDC)) == CS_CLASSDC, "class style not set\n");
193 hdc2 = GetDCEx(hwnd, NULL, 0);
194 ok(hdc2 == hdc1, "Expected the same DC, got %p\n", hdc2);
195 ok(ReleaseDC(hwnd, hdc2) == TRUE, "ReleaseDC failed\n");
196
197 SetClassLongPtrA(hwnd, GCL_STYLE, CS_OWNDC);
198
199 DestroyWindow(hwnd);
200 ok(UnregisterClass(pszClassName, GetModuleHandleA(0)) == TRUE,
201 "UnregisterClass failed");
202 }
203
204 static
205 void
206 Test_GetDCEx_CS_CLASSDC()
207 {
208 static const PSTR pszClassName = "TestClass_CS_CLASSDC";
209 ATOM atomClass;
210 HWND hwnd1, hwnd2;
211 HDC hdc1, hdc2;
212 //HRGN hrgn;
213
214 atomClass = RegisterClassHelper(pszClassName, CS_CLASSDC, WndProc);
215 ok(atomClass != 0, "Failed to register class\n");
216
217 hwnd1 = CreateWindowHelper(pszClassName, "Test Window1");
218 ok(hwnd1 != NULL, "Failed to create hwnd1\n");
219
220 /* Looks legit, but this is not the DC you are looking for!
221 In fact this is NOT the class dc, but an own DC, doh!
222 When the first Window is created, the DC for that Window is both it's own
223 AND the class DC. But we only get the class DC, when using DCX_USESTYLE */
224 hdc1 = GetDCEx(hwnd1, NULL, 0);
225 ok(hdc1 != NULL, "GetDCEx failed\n");
226 hdc2 = GetDCEx(hwnd1, NULL, 0);
227 ok(hdc2 == hdc1, "Expected the same DC, got %p\n", hdc2);
228 ok(ReleaseDC(hwnd1, hdc1) == TRUE, "ReleaseDC failed\n");
229 ok(ReleaseDC(hwnd1, hdc2) == TRUE, "ReleaseDC failed\n");
230
231 /* Now with DCX_USESTYLE */
232 hdc2 = GetDCEx(hwnd1, NULL, DCX_USESTYLE);
233 ok(hdc2 == hdc1, "Expected the same DC, got %p\n", hdc2);
234 ok(ReleaseDC(hwnd1, hdc2) == TRUE, "ReleaseDC failed\n");
235
236 hwnd2 = CreateWindowHelper(pszClassName, "Test Window2");
237 ok(hwnd2 != NULL, "Failed to create hwnd2\n");
238
239 /* Yeah, this doesn't work anymore. Once the */
240 hdc2 = GetDCEx(hwnd2, NULL, 0);
241 ok(hdc2 == NULL, "Expected failure\n");
242
243 /* Now with DCX_USESTYLE ... */
244 hdc2 = GetDCEx(hwnd2, NULL, DCX_USESTYLE);
245 ok(hdc2 == hdc1, "Expected the same DC, got %p\n", hdc2);
246 ok(ReleaseDC(hwnd2, hdc2) == TRUE, "ReleaseDC failed\n");
247
248 SendMessage(hwnd2, WM_USER, 0, 0);
249
250 DestroyWindow(hwnd1);
251 DestroyWindow(hwnd2);
252 ok(UnregisterClass(pszClassName, GetModuleHandleA(0)) == TRUE,
253 "UnregisterClass failed");
254 }
255
256 static
257 void
258 Test_GetDCEx_CS_Mixed()
259 {
260 static const PSTR pszClassName = "TestClass_CS_Mixed";
261 ATOM atomClass;
262 HWND hwnd1,hwnd2, hwnd3;
263 HDC hdc1, hdc2, hdc3;
264
265 /* Register a class with CS_OWNDC *and* CS_CLASSDC */
266 atomClass = RegisterClassHelper(pszClassName, CS_OWNDC | CS_CLASSDC, WndProc);
267 ok(atomClass != 0, "Failed to register class\n");
268
269 /* Create the first window, this should create a single own and class DC */
270 hwnd1 = CreateWindowHelper(pszClassName, "Test Window1");
271 ok(hwnd1 != NULL, "Failed to create hwnd1\n");
272
273 /* Verify that we have the right style */
274 ok(GetClassLongPtrA(hwnd1, GCL_STYLE) == (CS_OWNDC | CS_CLASSDC),
275 "class style not set\n");
276
277 /* This is now the class DC and the first windows own DC */
278 hdc1 = GetDCEx(hwnd1, NULL, 0);
279 ok(hdc1 != NULL, "GetDCEx failed\n");
280 ok(ReleaseDC(hwnd1, hdc1) == TRUE, "ReleaseDC failed\n");
281
282 /* This should get us the own/class DC again */
283 hdc2 = GetDCEx(hwnd1, NULL, 0);
284 ok(hdc2 == hdc1, "Expected the own/class DC, got %p\n", hdc2);
285 ok(ReleaseDC(hwnd1, hdc2) == TRUE, "ReleaseDC failed\n");
286
287 /* This should get us the class DC, but it's the same */
288 hdc2 = GetDCEx(hwnd1, NULL, DCX_USESTYLE);
289 ok(hdc2 == hdc1, "Expected the own/class DC, got %p\n", hdc2);
290 ok(ReleaseDC(hwnd1, hdc2) == TRUE, "ReleaseDC failed\n");
291
292 /* Create a second window */
293 hwnd2 = CreateWindowHelper(pszClassName, "Test Window1");
294 ok(hwnd1 != NULL, "Failed to create hwnd1\n");
295
296 /* This should get us the own DC of the new window */
297 hdc2 = GetDCEx(hwnd2, NULL, 0);
298 ok(hdc2 != NULL, "GetDCEx failed\n");
299 ok(hdc2 != hdc1, "Expected different DC\n");
300 ok(ReleaseDC(hwnd2, hdc2) == TRUE, "ReleaseDC failed\n");
301
302 /* This gets us the own DC again, CS_OWNDC has priority! */
303 hdc3 = GetDCEx(hwnd2, NULL, DCX_USESTYLE);
304 ok(hdc3 == hdc2, "Expected the own DC, got %p\n", hdc3);
305 ok(ReleaseDC(hwnd2, hdc3) == TRUE, "ReleaseDC failed\n");
306
307 /* Disable CS_OWNDC */
308 ok(SetClassLongPtrA(hwnd1, GCL_STYLE, CS_CLASSDC) == (CS_OWNDC | CS_CLASSDC), "unexpected style\n");
309 ok(GetClassLongPtrA(hwnd1, GCL_STYLE) == CS_CLASSDC, "class style not set\n");
310
311 /* Since the window already has an own DC, we get it again! */
312 hdc3 = GetDCEx(hwnd2, NULL, DCX_USESTYLE);
313 ok(hdc3 == hdc2, "Expected the own DC, got %p\n", hdc3);
314 ok(ReleaseDC(hwnd2, hdc3) == TRUE, "ReleaseDC failed\n");
315
316 /* Disable CS_CLASSDC, too */
317 ok(SetClassLongPtrA(hwnd1, GCL_STYLE, 0) == CS_CLASSDC, "unexpected style\n");
318 ok(GetClassLongPtrA(hwnd1, GCL_STYLE) == 0, "class style not set\n");
319
320 /* With DCX_USESTYLE we only get a cached DC */
321 hdc3 = GetDCEx(hwnd2, NULL, DCX_USESTYLE);
322 ok(hdc3 != NULL, "GetDCEx failed\n");
323 ok(hdc3 != hdc1, "Expected different DC, got class DC\n");
324 ok(hdc3 != hdc2, "Expected different DC, got own DC\n");
325 ok(ReleaseDC(hwnd2, hdc3) == TRUE, "ReleaseDC failed\n");
326
327 /* Without DCX_USESTYLE we get the own DC */
328 hdc3 = GetDCEx(hwnd2, NULL, 0);
329 ok(hdc3 != NULL, "GetDCEx failed\n");
330 ok(hdc3 != hdc1, "Expected different DC, got class DC\n");
331 ok(hdc3 == hdc2, "Expected the own DC, got %p\n", hdc3);
332 ok(ReleaseDC(hwnd2, hdc3) == TRUE, "ReleaseDC failed\n");
333
334 /* Set only CS_OWNDC */
335 ok(SetClassLongPtrA(hwnd1, GCL_STYLE, CS_OWNDC) == 0, "unexpected style\n");
336 ok(GetClassLongPtrA(hwnd1, GCL_STYLE) == CS_OWNDC, "class style not set\n");
337
338 hwnd3 = CreateWindowHelper(pszClassName, "Test Window1");
339 ok(hwnd3 != NULL, "Failed to create hwnd1\n");
340
341 /* This should get a new own DC */
342 hdc2 = GetDCEx(hwnd3, NULL, 0);
343 ok(hdc2 != hdc1, "Expected different DC\n");
344 ok(ReleaseDC(hwnd3, hdc2) == TRUE, "ReleaseDC failed\n");
345
346 /* Re-enable CS_CLASSDC */
347 ok(SetClassLongPtrA(hwnd1, GCL_STYLE, (CS_OWNDC | CS_CLASSDC)) == CS_OWNDC, "unexpected style\n");
348 ok(GetClassLongPtrA(hwnd1, GCL_STYLE) == (CS_OWNDC | CS_CLASSDC), "class style not set\n");
349
350 /* This should get us the own DC */
351 hdc3 = GetDCEx(hwnd3, NULL, 0);
352 ok(hdc3 == hdc2, "Expected the same DC, got %p\n", hdc3);
353 ok(ReleaseDC(hwnd3, hdc3) == TRUE, "ReleaseDC failed\n");
354
355 /* This should still get us the new own DC */
356 hdc3 = GetDCEx(hwnd3, NULL, DCX_USESTYLE);
357 ok(hdc3 == hdc2, "Expected the same DC, got %p\n", hdc3);
358 ok(ReleaseDC(hwnd3, hdc3) == TRUE, "ReleaseDC failed\n");
359
360 /* Disable CS_OWNDC */
361 ok(SetClassLongPtrA(hwnd1, GCL_STYLE, CS_CLASSDC) == (CS_OWNDC | CS_CLASSDC), "unexpected style\n");
362 ok(GetClassLongPtrA(hwnd1, GCL_STYLE) == CS_CLASSDC, "class style not set\n");
363
364 /* This should get us the own DC */
365 hdc3 = GetDCEx(hwnd3, NULL, 0);
366 ok(hdc3 == hdc2, "Expected the same DC, got %p\n", hdc3);
367 ok(ReleaseDC(hwnd3, hdc3) == TRUE, "ReleaseDC failed\n");
368
369 /* This should still get us the new own DC */
370 hdc3 = GetDCEx(hwnd3, NULL, DCX_USESTYLE);
371 ok(hdc3 == hdc2, "Expected the same DC, got %p\n", hdc3);
372 ok(ReleaseDC(hwnd3, hdc3) == TRUE, "ReleaseDC failed\n");
373
374 /* cleanup for a second run */
375 DestroyWindow(hwnd1);
376 DestroyWindow(hwnd2);
377 DestroyWindow(hwnd3);
378 ok(UnregisterClass(pszClassName, GetModuleHandleA(0)) == TRUE,
379 "UnregisterClass failed\n");
380
381 /* Create class again with CS_OWNDC */
382 atomClass = RegisterClassHelper(pszClassName, CS_OWNDC, WndProc);
383 ok(atomClass != 0, "Failed to register class\n");
384
385 hwnd1 = CreateWindowHelper(pszClassName, "Test Window1");
386 ok(hwnd1 != NULL, "Failed to create hwnd1\n");
387
388 /* This is the windows own DC, the class does not have a class DC yet */
389 hdc1 = GetDCEx(hwnd1, NULL, 0);
390 ok(hdc1 != NULL, "GetDCEx failed\n");
391 ok(ReleaseDC(hwnd1, hdc1) == TRUE, "ReleaseDC failed\n");
392
393 /* Enable only CS_CLASSDC */
394 ok(SetClassLongPtrA(hwnd1, GCL_STYLE, CS_CLASSDC) == CS_OWNDC, "unexpected style\n");
395 ok(GetClassLongPtrA(hwnd1, GCL_STYLE) == CS_CLASSDC, "class style not set\n");
396
397 /* Create a second window. Now we should create a class DC! */
398 hwnd2 = CreateWindowHelper(pszClassName, "Test Window2");
399 ok(hwnd2 != NULL, "Failed to create hwnd1\n");
400
401 /* We expect a new DCE (the class DCE) */
402 hdc2 = GetDCEx(hwnd2, NULL, DCX_USESTYLE);
403 ok(hdc2 != NULL, "GetDCEx failed\n");
404 ok(hdc2 != hdc1, "Expected different DCs\n");
405 ok(ReleaseDC(hwnd2, hdc2) == TRUE, "ReleaseDC failed\n");
406
407 /* cleanup */
408 DestroyWindow(hwnd1);
409 DestroyWindow(hwnd2);
410 ok(UnregisterClass(pszClassName, GetModuleHandleA(0)) == TRUE,
411 "UnregisterClass failed\n");
412 }
413
414 static
415 void
416 Test_GetDCEx_CS_SwitchedStyle()
417 {
418 static const PSTR pszClassName = "TestClass_CS_SwitchedStyle";
419 ATOM atomClass;
420 HWND hwnd1, hwnd2;
421
422 atomClass = RegisterClassHelper(pszClassName, CS_OWNDC, WndProc);
423 ok(atomClass != 0, "Failed to register class\n");
424
425 hwnd1 = CreateWindowHelper(pszClassName, "Test Window1");
426 ok(hwnd1 != NULL, "Failed to create hwnd1\n");
427
428 ok(SetClassLongPtrA(hwnd1, GCL_STYLE, CS_CLASSDC) == CS_OWNDC, "unexpected style\n");
429 ok(GetClassLongPtrA(hwnd1, GCL_STYLE) == CS_CLASSDC, "class style not set\n");
430
431 hwnd2 = CreateWindowHelper(pszClassName, "Test Window2");
432 ok(hwnd2 != NULL, "Failed to create hwnd2\n");
433
434 DestroyWindow(hwnd1);
435 DestroyWindow(hwnd2);
436 ok(UnregisterClass(pszClassName, GetModuleHandleA(0)) == TRUE,
437 "UnregisterClass failed\n");
438 }
439
440 START_TEST(GetDCEx)
441 {
442 Test_GetDCEx_Params();
443 Test_GetDCEx_Cached();
444 Test_GetDCEx_CS_OWNDC();
445 Test_GetDCEx_CS_CLASSDC();
446 Test_GetDCEx_CS_Mixed();
447 Test_GetDCEx_CS_SwitchedStyle();
448 }
449