gdi32: Fix the DeleteDC test failures under Win9x.
[wine] / dlls / gdi32 / tests / dc.c
1 /*
2  * Unit tests for dc functions
3  *
4  * Copyright (c) 2005 Huw Davies
5  * Copyright (c) 2005 Dmitry Timoshkov
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #define WINVER 0x0501 /* request latest DEVMODE */
23
24 #include <assert.h>
25 #include <stdio.h>
26
27 #include "wine/test.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "winerror.h"
32
33 static void dump_region(HRGN hrgn)
34 {
35     DWORD i, size;
36     RGNDATA *data = NULL;
37     RECT *rect;
38
39     if (!hrgn)
40     {
41         printf( "(null) region\n" );
42         return;
43     }
44     if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
45     if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
46     GetRegionData( hrgn, size, data );
47     printf( "%d rects:", data->rdh.nCount );
48     for (i = 0, rect = (RECT *)data->Buffer; i < data->rdh.nCount; i++, rect++)
49         printf( " (%d,%d)-(%d,%d)", rect->left, rect->top, rect->right, rect->bottom );
50     printf( "\n" );
51     HeapFree( GetProcessHeap(), 0, data );
52 }
53
54 static void test_savedc_2(void)
55 {
56     HWND hwnd;
57     HDC hdc;
58     HRGN hrgn;
59     RECT rc, rc_clip;
60     int ret;
61
62     hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
63                            0, 0, 0, NULL);
64     assert(hwnd != 0);
65     ShowWindow(hwnd, SW_SHOW);
66     UpdateWindow(hwnd);
67
68     hrgn = CreateRectRgn(0, 0, 0, 0);
69     assert(hrgn != 0);
70
71     hdc = GetDC(hwnd);
72     ok(hdc != NULL, "GetDC failed\n");
73
74     ret = GetClipBox(hdc, &rc_clip);
75     ok(ret == SIMPLEREGION, "GetClipBox returned %d instead of SIMPLEREGION\n", ret);
76     ret = GetClipRgn(hdc, hrgn);
77     ok(ret == 0, "GetClipRgn returned %d instead of 0\n", ret);
78     ret = GetRgnBox(hrgn, &rc);
79     ok(ret == NULLREGION, "GetRgnBox returned %d (%d,%d-%d,%d) instead of NULLREGION\n",
80        ret, rc.left, rc.top, rc.right, rc.bottom);
81     /*dump_region(hrgn);*/
82     SetRect(&rc, 0, 0, 100, 100);
83     ok(EqualRect(&rc, &rc_clip),
84        "rects are not equal: (%d,%d-%d,%d) - (%d,%d-%d,%d)\n",
85        rc.left, rc.top, rc.right, rc.bottom,
86        rc_clip.left, rc_clip.top, rc_clip.right, rc_clip.bottom);
87
88     ret = SaveDC(hdc);
89 todo_wine
90 {
91     ok(ret == 1, "ret = %d\n", ret);
92 }
93
94     ret = IntersectClipRect(hdc, 0, 0, 50, 50);
95     if (ret == COMPLEXREGION)
96     {
97         /* XP returns COMPLEXREGION although dump_region reports only 1 rect */
98         trace("Windows BUG: IntersectClipRect returned %d instead of SIMPLEREGION\n", ret);
99         /* let's make sure that it's a simple region */
100         ret = GetClipRgn(hdc, hrgn);
101         ok(ret == 1, "GetClipRgn returned %d instead of 1\n", ret);
102         dump_region(hrgn);
103     }
104     else
105         ok(ret == SIMPLEREGION, "IntersectClipRect returned %d instead of SIMPLEREGION\n", ret);
106
107     ret = GetClipBox(hdc, &rc_clip);
108     ok(ret == SIMPLEREGION, "GetClipBox returned %d instead of SIMPLEREGION\n", ret);
109     SetRect(&rc, 0, 0, 50, 50);
110     ok(EqualRect(&rc, &rc_clip), "rects are not equal\n");
111
112     ret = RestoreDC(hdc, 1);
113     ok(ret, "ret = %d\n", ret);
114
115     ret = GetClipBox(hdc, &rc_clip);
116     ok(ret == SIMPLEREGION, "GetClipBox returned %d instead of SIMPLEREGION\n", ret);
117     SetRect(&rc, 0, 0, 100, 100);
118     ok(EqualRect(&rc, &rc_clip), "rects are not equal\n");
119
120     DeleteObject(hrgn);
121     ReleaseDC(hwnd, hdc);
122     DestroyWindow(hwnd);
123 }
124
125 static void test_savedc(void)
126 {
127     HDC hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
128     int ret;
129
130     ok(hdc != NULL, "CreateDC rets %p\n", hdc);
131
132     ret = SaveDC(hdc);
133     ok(ret == 1, "ret = %d\n", ret);
134     ret = SaveDC(hdc);
135     ok(ret == 2, "ret = %d\n", ret);
136     ret = SaveDC(hdc);
137     ok(ret == 3, "ret = %d\n", ret);
138     ret = RestoreDC(hdc, -1);
139     ok(ret, "ret = %d\n", ret);
140     ret = SaveDC(hdc);
141     ok(ret == 3, "ret = %d\n", ret);
142     ret = RestoreDC(hdc, 1);
143     ok(ret, "ret = %d\n", ret);
144     ret = SaveDC(hdc);
145     ok(ret == 1, "ret = %d\n", ret);
146     ret = SaveDC(hdc);
147     ok(ret == 2, "ret = %d\n", ret);
148     ret = SaveDC(hdc);
149     ok(ret == 3, "ret = %d\n", ret);
150     ret = RestoreDC(hdc, -2);
151     ok(ret, "ret = %d\n", ret);
152     ret = SaveDC(hdc);
153     ok(ret == 2, "ret = %d\n", ret);
154     ret = RestoreDC(hdc, -2);
155     ok(ret, "ret = %d\n", ret);
156     ret = SaveDC(hdc);
157     ok(ret == 1, "ret = %d\n", ret);
158     ret = SaveDC(hdc);
159     ok(ret == 2, "ret = %d\n", ret); 
160     ret = RestoreDC(hdc, -4);
161     ok(!ret, "ret = %d\n", ret);
162     ret = RestoreDC(hdc, 3);
163     ok(!ret, "ret = %d\n", ret);
164
165     /* Under win98 the following two succeed and both clear the save stack
166     ret = RestoreDC(hdc, -3);
167     ok(!ret, "ret = %d\n", ret);
168     ret = RestoreDC(hdc, 0);
169     ok(!ret, "ret = %d\n", ret);
170     */
171
172     ret = RestoreDC(hdc, 1);
173     ok(ret, "ret = %d\n", ret);
174
175     DeleteDC(hdc);
176 }
177
178 static void test_GdiConvertToDevmodeW(void)
179 {
180     DEVMODEW * (WINAPI *pGdiConvertToDevmodeW)(const DEVMODEA *);
181     DEVMODEA dmA;
182     DEVMODEW *dmW;
183     BOOL ret;
184
185     pGdiConvertToDevmodeW = (void *)GetProcAddress(GetModuleHandleA("gdi32.dll"), "GdiConvertToDevmodeW");
186     if (!pGdiConvertToDevmodeW)
187     {
188         win_skip("GdiConvertToDevmodeW is not available on this platform\n");
189         return;
190     }
191
192     ret = EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &dmA);
193     ok(ret, "EnumDisplaySettingsExA error %u\n", GetLastError());
194     ok(dmA.dmSize >= FIELD_OFFSET(DEVMODEA, dmICMMethod), "dmSize is too small: %04x\n", dmA.dmSize);
195     ok(dmA.dmSize <= sizeof(DEVMODEA), "dmSize is too large: %04x\n", dmA.dmSize);
196
197     dmW = pGdiConvertToDevmodeW(&dmA);
198     ok(dmW->dmSize >= FIELD_OFFSET(DEVMODEW, dmICMMethod), "dmSize is too small: %04x\n", dmW->dmSize);
199     ok(dmW->dmSize <= sizeof(DEVMODEW), "dmSize is too large: %04x\n", dmW->dmSize);
200     HeapFree(GetProcessHeap(), 0, dmW);
201
202     dmA.dmSize = FIELD_OFFSET(DEVMODEA, dmFields) + sizeof(dmA.dmFields);
203     dmW = pGdiConvertToDevmodeW(&dmA);
204     ok(dmW->dmSize == FIELD_OFFSET(DEVMODEW, dmFields) + sizeof(dmW->dmFields),
205        "wrong size %u\n", dmW->dmSize);
206     HeapFree(GetProcessHeap(), 0, dmW);
207
208     dmA.dmICMMethod = DMICMMETHOD_NONE;
209     dmA.dmSize = FIELD_OFFSET(DEVMODEA, dmICMMethod) + sizeof(dmA.dmICMMethod);
210     dmW = pGdiConvertToDevmodeW(&dmA);
211     ok(dmW->dmSize == FIELD_OFFSET(DEVMODEW, dmICMMethod) + sizeof(dmW->dmICMMethod),
212        "wrong size %u\n", dmW->dmSize);
213     ok(dmW->dmICMMethod == DMICMMETHOD_NONE,
214        "expected DMICMMETHOD_NONE, got %u\n", dmW->dmICMMethod);
215     HeapFree(GetProcessHeap(), 0, dmW);
216
217     dmA.dmSize = 1024;
218     dmW = pGdiConvertToDevmodeW(&dmA);
219     ok(dmW->dmSize == FIELD_OFFSET(DEVMODEW, dmPanningHeight) + sizeof(dmW->dmPanningHeight),
220        "wrong size %u\n", dmW->dmSize);
221     HeapFree(GetProcessHeap(), 0, dmW);
222
223     SetLastError(0xdeadbeef);
224     dmA.dmSize = 0;
225     dmW = pGdiConvertToDevmodeW(&dmA);
226     ok(!dmW, "GdiConvertToDevmodeW should fail\n");
227     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %u\n", GetLastError());
228
229     /* this is the minimal dmSize that XP accepts */
230     dmA.dmSize = FIELD_OFFSET(DEVMODEA, dmFields);
231     dmW = pGdiConvertToDevmodeW(&dmA);
232     ok(dmW->dmSize == FIELD_OFFSET(DEVMODEW, dmFields),
233        "expected %04x, got %04x\n", FIELD_OFFSET(DEVMODEW, dmFields), dmW->dmSize);
234     HeapFree(GetProcessHeap(), 0, dmW);
235 }
236
237 static void test_CreateCompatibleDC(void)
238 {
239     BOOL bRet;
240     HDC hDC;
241     HDC hNewDC;
242
243     /* Create a DC compatible with the screen */
244     hDC = CreateCompatibleDC(NULL);
245     ok(hDC != NULL, "CreateCompatibleDC returned %p\n", hDC);
246
247     /* Delete this DC, this should succeed */
248     bRet = DeleteDC(hDC);
249     ok(bRet == TRUE, "DeleteDC returned %u\n", bRet);
250
251     /* Try to create a DC compatible to the deleted DC. This has to fail */
252     hNewDC = CreateCompatibleDC(hDC);
253     ok(hNewDC == NULL, "CreateCompatibleDC returned %p\n", hNewDC);
254 }
255
256 static void test_DC_bitmap(void)
257 {
258     HDC hdc, hdcmem;
259     DWORD bits[64];
260     HBITMAP hbmp, oldhbmp;
261     COLORREF col;
262     int i, bitspixel;
263
264     /* fill bitmap data with b&w pattern */
265     for( i = 0; i < 64; i++) bits[i] = i & 1 ? 0 : 0xffffff;
266
267     hdc = GetDC(0);
268     ok( hdc != NULL, "CreateDC rets %p\n", hdc);
269     bitspixel = GetDeviceCaps( hdc, BITSPIXEL);
270     /* create a memory dc */
271     hdcmem = CreateCompatibleDC( hdc);
272     ok( hdcmem != NULL, "CreateCompatibleDC rets %p\n", hdcmem);
273     /* tests */
274     /* test monochrome bitmap: should always work */
275     hbmp = CreateBitmap(32, 32, 1, 1, bits);
276     ok( hbmp != NULL, "CreateBitmap returns %p\n", hbmp);
277     oldhbmp = SelectObject( hdcmem, hbmp);
278     ok( oldhbmp != NULL, "SelectObject returned NULL\n" ); /* a memdc always has a bitmap selected */
279     col = GetPixel( hdcmem, 0, 0);
280     ok( col == 0xffffff, "GetPixel returned %08x, expected 00ffffff\n", col);
281     col = GetPixel( hdcmem, 1, 1);
282     ok( col == 0x000000, "GetPixel returned %08x, expected 00000000\n", col);
283     col = GetPixel( hdcmem, 100, 1);
284     ok( col == CLR_INVALID, "GetPixel returned %08x, expected ffffffff\n", col);
285     SelectObject( hdcmem, oldhbmp);
286     DeleteObject( hbmp);
287
288     /* test with 2 bits color depth, not likely to succeed */
289     hbmp = CreateBitmap(16, 16, 1, 2, bits);
290     ok( hbmp != NULL, "CreateBitmap returns %p\n", hbmp);
291     oldhbmp = SelectObject( hdcmem, hbmp);
292     if( bitspixel != 2)
293         ok( !oldhbmp, "SelectObject of a bitmap with 2 bits/pixel should return  NULL\n");
294     if( oldhbmp) SelectObject( hdcmem, oldhbmp);
295     DeleteObject( hbmp);
296
297     /* test with 16 bits color depth, might succeed */
298     hbmp = CreateBitmap(6, 6, 1, 16, bits);
299     ok( hbmp != NULL, "CreateBitmap returns %p\n", hbmp);
300     oldhbmp = SelectObject( hdcmem, hbmp);
301     if( bitspixel == 16) {
302         ok( oldhbmp != NULL, "SelectObject returned NULL\n" );
303         col = GetPixel( hdcmem, 0, 0);
304         ok( col == 0xffffff,
305             "GetPixel of a bitmap with 16 bits/pixel returned %08x, expected 00ffffff\n", col);
306         col = GetPixel( hdcmem, 1, 1);
307         ok( col == 0x000000,
308             "GetPixel of a bitmap with 16 bits/pixel returned returned %08x, expected 00000000\n", col);
309     }
310     if( oldhbmp) SelectObject( hdcmem, oldhbmp);
311     DeleteObject( hbmp);
312
313     /* test with 32 bits color depth, probably succeed */
314     hbmp = CreateBitmap(4, 4, 1, 32, bits);
315     ok( hbmp != NULL, "CreateBitmap returns %p\n", hbmp);
316     oldhbmp = SelectObject( hdcmem, hbmp);
317     if( bitspixel == 32) {
318         ok( oldhbmp != NULL, "SelectObject returned NULL\n" );
319         col = GetPixel( hdcmem, 0, 0);
320         ok( col == 0xffffff,
321             "GetPixel of a bitmap with 32 bits/pixel returned %08x, expected 00ffffff\n", col);
322         col = GetPixel( hdcmem, 1, 1);
323         ok( col == 0x000000,
324             "GetPixel of a bitmap with 32 bits/pixel returned returned %08x, expected 00000000\n", col);
325     }
326     if( oldhbmp) SelectObject( hdcmem, oldhbmp);
327     DeleteObject( hbmp);
328     ReleaseDC( 0, hdc );
329 }
330
331 static void test_DeleteDC(void)
332 {
333     HWND hwnd;
334     HDC hdc, hdc_test;
335     WNDCLASSEX cls;
336     int ret;
337
338     /* window DC */
339     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP|WS_VISIBLE, 0,0,100,100,
340                            0, 0, 0, NULL);
341     ok(hwnd != 0, "CreateWindowExA failed\n");
342
343     hdc = GetDC(hwnd);
344     ok(hdc != 0, "GetDC failed\n");
345     ret = GetObjectType(hdc);
346     ok(ret == OBJ_DC, "expected OBJ_DC, got %d\n", ret);
347     ret = DeleteDC(hdc);
348     ok(ret, "DeleteDC failed\n");
349     ret = GetObjectType(hdc);
350     ok(!ret || broken(ret) /* win9x */, "GetObjectType should fail for a deleted DC\n");
351
352     hdc = GetWindowDC(hwnd);
353     ok(hdc != 0, "GetDC failed\n");
354     ret = GetObjectType(hdc);
355     ok(ret == OBJ_DC, "expected OBJ_DC, got %d\n", ret);
356     ret = DeleteDC(hdc);
357     ok(ret, "DeleteDC failed\n");
358     ret = GetObjectType(hdc);
359     ok(!ret || broken(ret) /* win9x */, "GetObjectType should fail for a deleted DC\n");
360
361     DestroyWindow(hwnd);
362
363     /* desktop window DC */
364     hwnd = GetDesktopWindow();
365     ok(hwnd != 0, "GetDesktopWindow failed\n");
366
367     hdc = GetDC(hwnd);
368     ok(hdc != 0, "GetDC failed\n");
369     ret = GetObjectType(hdc);
370     ok(ret == OBJ_DC, "expected OBJ_DC, got %d\n", ret);
371     ret = DeleteDC(hdc);
372     ok(ret, "DeleteDC failed\n");
373     ret = GetObjectType(hdc);
374     ok(!ret || broken(ret) /* win9x */, "GetObjectType should fail for a deleted DC\n");
375
376     hdc = GetWindowDC(hwnd);
377     ok(hdc != 0, "GetDC failed\n");
378     ret = GetObjectType(hdc);
379     ok(ret == OBJ_DC, "expected OBJ_DC, got %d\n", ret);
380     ret = DeleteDC(hdc);
381     ok(ret, "DeleteDC failed\n");
382     ret = GetObjectType(hdc);
383     ok(!ret || broken(ret) /* win9x */, "GetObjectType should fail for a deleted DC\n");
384
385     /* CS_CLASSDC */
386     memset(&cls, 0, sizeof(cls));
387     cls.cbSize = sizeof(cls);
388     cls.style = CS_CLASSDC;
389     cls.hInstance = GetModuleHandle(0);
390     cls.lpszClassName = "Wine class DC";
391     cls.lpfnWndProc = DefWindowProcA;
392     ret = RegisterClassExA(&cls);
393     ok(ret, "RegisterClassExA failed\n");
394
395     hwnd = CreateWindowExA(0, "Wine class DC", NULL, WS_POPUP|WS_VISIBLE, 0,0,100,100,
396                            0, 0, 0, NULL);
397     ok(hwnd != 0, "CreateWindowExA failed\n");
398
399     hdc = GetDC(hwnd);
400     ok(hdc != 0, "GetDC failed\n");
401     ret = GetObjectType(hdc);
402     ok(ret == OBJ_DC, "expected OBJ_DC, got %d\n", ret);
403     ret = DeleteDC(hdc);
404     ok(ret, "DeleteDC failed\n");
405     ret = GetObjectType(hdc);
406     ok(ret == OBJ_DC, "expected OBJ_DC, got %d\n", ret);
407     ret = ReleaseDC(hwnd, hdc);
408     ok(ret, "ReleaseDC failed\n");
409     ret = GetObjectType(hdc);
410     ok(ret == OBJ_DC, "expected OBJ_DC, got %d\n", ret);
411
412     hdc_test = hdc;
413
414     hdc = GetWindowDC(hwnd);
415     ok(hdc != 0, "GetDC failed\n");
416     ret = GetObjectType(hdc);
417     ok(ret == OBJ_DC, "expected OBJ_DC, got %d\n", ret);
418     ret = DeleteDC(hdc);
419     ok(ret, "DeleteDC failed\n");
420     ret = GetObjectType(hdc);
421     ok(!ret || broken(ret) /* win9x */, "GetObjectType should fail for a deleted DC\n");
422
423     DestroyWindow(hwnd);
424
425     ret = GetObjectType(hdc_test);
426     ok(ret == OBJ_DC, "expected OBJ_DC, got %d\n", ret);
427
428     ret = UnregisterClassA("Wine class DC", GetModuleHandle(NULL));
429     ok(ret, "UnregisterClassA failed\n");
430
431     ret = GetObjectType(hdc_test);
432 todo_wine
433     ok(!ret, "GetObjectType should fail for a deleted DC\n");
434
435     /* CS_OWNDC */
436     memset(&cls, 0, sizeof(cls));
437     cls.cbSize = sizeof(cls);
438     cls.style = CS_OWNDC;
439     cls.hInstance = GetModuleHandle(0);
440     cls.lpszClassName = "Wine own DC";
441     cls.lpfnWndProc = DefWindowProcA;
442     ret = RegisterClassExA(&cls);
443     ok(ret, "RegisterClassExA failed\n");
444
445     hwnd = CreateWindowExA(0, "Wine own DC", NULL, WS_POPUP|WS_VISIBLE, 0,0,100,100,
446                            0, 0, 0, NULL);
447     ok(hwnd != 0, "CreateWindowExA failed\n");
448
449     hdc = GetDC(hwnd);
450     ok(hdc != 0, "GetDC failed\n");
451     ret = GetObjectType(hdc);
452     ok(ret == OBJ_DC, "expected OBJ_DC, got %d\n", ret);
453     ret = DeleteDC(hdc);
454     ok(ret, "DeleteDC failed\n");
455     ret = GetObjectType(hdc);
456     ok(ret == OBJ_DC, "expected OBJ_DC, got %d\n", ret);
457     ret = ReleaseDC(hwnd, hdc);
458     ok(ret, "ReleaseDC failed\n");
459     ret = GetObjectType(hdc);
460     ok(ret == OBJ_DC, "expected OBJ_DC, got %d\n", ret);
461
462     hdc = GetWindowDC(hwnd);
463     ok(hdc != 0, "GetDC failed\n");
464     ret = GetObjectType(hdc);
465     ok(ret == OBJ_DC, "expected OBJ_DC, got %d\n", ret);
466     ret = DeleteDC(hdc);
467     ok(ret, "DeleteDC failed\n");
468     ret = GetObjectType(hdc);
469     ok(!ret || broken(ret) /* win9x */, "GetObjectType should fail for a deleted DC\n");
470
471     DestroyWindow(hwnd);
472
473     ret = UnregisterClassA("Wine own DC", GetModuleHandle(NULL));
474     ok(ret, "UnregisterClassA failed\n");
475 }
476
477 START_TEST(dc)
478 {
479     test_savedc();
480     test_savedc_2();
481     test_GdiConvertToDevmodeW();
482     test_CreateCompatibleDC();
483     test_DC_bitmap();
484     test_DeleteDC();
485 }