1 /*
2  * Unit test suite for GDI objects
3  *
4  * Copyright 2002 Mike McCormack
5  * Copyright 2004 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 #include "precomp.h"
23 
24 static void test_gdi_objects(void)
25 {
26     BYTE buff[256];
27     HDC hdc = GetDC(NULL);
28     HPEN hp;
29     int i;
30     BOOL ret;
31 
32     /* SelectObject() with a NULL DC returns 0 and sets ERROR_INVALID_HANDLE.
33      * Note: Under XP at least invalid ptrs can also be passed, not just NULL;
34      *       Don't test that here in case it crashes earlier win versions.
35      */
36     SetLastError(0);
37     hp = SelectObject(NULL, GetStockObject(BLACK_PEN));
38     ok(!hp && (GetLastError() == ERROR_INVALID_HANDLE || broken(!GetLastError())),
39        "SelectObject(NULL DC) expected 0, ERROR_INVALID_HANDLE, got %p, %u\n",
40        hp, GetLastError());
41 
42     /* With a valid DC and a NULL object, the call returns 0 but does not SetLastError() */
43     SetLastError(0);
44     hp = SelectObject(hdc, NULL);
45     ok(!hp && !GetLastError(),
46        "SelectObject(NULL obj) expected 0, NO_ERROR, got %p, %u\n",
47        hp, GetLastError());
48 
49     /* The DC is unaffected by the NULL SelectObject */
50     SetLastError(0);
51     hp = SelectObject(hdc, GetStockObject(BLACK_PEN));
52     ok(hp && !GetLastError(),
53        "SelectObject(post NULL) expected non-null, NO_ERROR, got %p, %u\n",
54        hp, GetLastError());
55 
56     /* GetCurrentObject does not SetLastError() on a null object */
57     SetLastError(0);
58     hp = GetCurrentObject(NULL, OBJ_PEN);
59     ok(!hp && !GetLastError(),
60        "GetCurrentObject(NULL DC) expected 0, NO_ERROR, got %p, %u\n",
61        hp, GetLastError());
62 
63     /* DeleteObject does not SetLastError() on a null object */
64     ret = DeleteObject(NULL);
65     ok( !ret && !GetLastError(),
66        "DeleteObject(NULL obj), expected 0, NO_ERROR, got %d, %u\n",
67        ret, GetLastError());
68 
69     /* GetObject does not SetLastError() on a null object */
70     SetLastError(0);
71     i = GetObjectA(NULL, sizeof(buff), buff);
72     ok (!i && (GetLastError() == 0 || GetLastError() == ERROR_INVALID_PARAMETER),
73         "GetObject(NULL obj), expected 0, NO_ERROR, got %d, %u\n",
74 	i, GetLastError());
75 
76     /* GetObject expects ERROR_NOACCESS when passed an invalid buffer */
77     hp = SelectObject(hdc, GetStockObject(BLACK_PEN));
78     SetLastError(0);
79     i = GetObjectA(hp, (INT_PTR)buff, (LPVOID)sizeof(buff));
80     ok (!i && (GetLastError() == 0 || GetLastError() == ERROR_NOACCESS),
81         "GetObject(invalid buff), expected 0, ERROR_NOACCESS, got %d, %u\n",
82     i, GetLastError());
83 
84     /* GetObjectType does SetLastError() on a null object */
85     SetLastError(0);
86     i = GetObjectType(NULL);
87     ok (!i && GetLastError() == ERROR_INVALID_HANDLE,
88         "GetObjectType(NULL obj), expected 0, ERROR_INVALID_HANDLE, got %d, %u\n",
89         i, GetLastError());
90 
91     /* UnrealizeObject does not SetLastError() on a null object */
92     SetLastError(0);
93     i = UnrealizeObject(NULL);
94     ok (!i && !GetLastError(),
95         "UnrealizeObject(NULL obj), expected 0, NO_ERROR, got %d, %u\n",
96         i, GetLastError());
97 
98     ReleaseDC(NULL, hdc);
99 }
100 
101 struct hgdiobj_event
102 {
103     HDC hdc;
104     HGDIOBJ hgdiobj1;
105     HGDIOBJ hgdiobj2;
106     HANDLE stop_event;
107     HANDLE ready_event;
108 };
109 
110 static DWORD WINAPI thread_proc(void *param)
111 {
112     LOGPEN lp;
113     DWORD status;
114     struct hgdiobj_event *hgdiobj_event = param;
115 
116     hgdiobj_event->hdc = CreateDCA("display", NULL, NULL, NULL);
117     ok(hgdiobj_event->hdc != NULL, "CreateDC error %u\n", GetLastError());
118 
119     hgdiobj_event->hgdiobj1 = CreatePen(PS_DASHDOTDOT, 17, RGB(1, 2, 3));
120     ok(hgdiobj_event->hgdiobj1 != 0, "Failed to create pen\n");
121 
122     hgdiobj_event->hgdiobj2 = CreateRectRgn(0, 1, 12, 17);
123     ok(hgdiobj_event->hgdiobj2 != 0, "Failed to create pen\n");
124 
125     SetEvent(hgdiobj_event->ready_event);
126     status = WaitForSingleObject(hgdiobj_event->stop_event, INFINITE);
127     ok(status == WAIT_OBJECT_0, "WaitForSingleObject error %u\n", GetLastError());
128 
129     ok(!GetObjectA(hgdiobj_event->hgdiobj1, sizeof(lp), &lp), "GetObject should fail\n");
130 
131     ok(!GetDeviceCaps(hgdiobj_event->hdc, TECHNOLOGY), "GetDeviceCaps(TECHNOLOGY) should fail\n");
132 
133     return 0;
134 }
135 
136 static void test_thread_objects(void)
137 {
138     LOGPEN lp;
139     DWORD tid, type;
140     HANDLE hthread;
141     struct hgdiobj_event hgdiobj_event;
142     INT ret;
143     DWORD status;
144     BOOL bRet;
145 
146     hgdiobj_event.stop_event = CreateEventA(NULL, 0, 0, NULL);
147     ok(hgdiobj_event.stop_event != NULL, "CreateEvent error %u\n", GetLastError());
148     hgdiobj_event.ready_event = CreateEventA(NULL, 0, 0, NULL);
149     ok(hgdiobj_event.ready_event != NULL, "CreateEvent error %u\n", GetLastError());
150 
151     hthread = CreateThread(NULL, 0, thread_proc, &hgdiobj_event, 0, &tid);
152     ok(hthread != NULL, "CreateThread error %u\n", GetLastError());
153 
154     status = WaitForSingleObject(hgdiobj_event.ready_event, INFINITE);
155     ok(status == WAIT_OBJECT_0, "WaitForSingleObject error %u\n", GetLastError());
156 
157     ret = GetObjectA(hgdiobj_event.hgdiobj1, sizeof(lp), &lp);
158     ok(ret == sizeof(lp), "GetObject error %u\n", GetLastError());
159     ok(lp.lopnStyle == PS_DASHDOTDOT, "wrong pen style %d\n", lp.lopnStyle);
160     ok(lp.lopnWidth.x == 17, "wrong pen width.y %d\n", lp.lopnWidth.x);
161     ok(lp.lopnWidth.y == 0, "wrong pen width.y %d\n", lp.lopnWidth.y);
162     ok(lp.lopnColor == RGB(1, 2, 3), "wrong pen width.y %08x\n", lp.lopnColor);
163 
164     ret = GetDeviceCaps(hgdiobj_event.hdc, TECHNOLOGY);
165     ok(ret == DT_RASDISPLAY, "GetDeviceCaps(TECHNOLOGY) should return DT_RASDISPLAY not %d\n", ret);
166 
167     bRet = DeleteObject(hgdiobj_event.hgdiobj1);
168     ok(bRet, "DeleteObject error %u\n", GetLastError());
169     bRet = DeleteDC(hgdiobj_event.hdc);
170     ok(bRet, "DeleteDC error %u\n", GetLastError());
171 
172     type = GetObjectType(hgdiobj_event.hgdiobj2);
173     ok(type == OBJ_REGION, "GetObjectType returned %u\n", type);
174 
175     SetEvent(hgdiobj_event.stop_event);
176     status = WaitForSingleObject(hthread, INFINITE);
177     ok(status == WAIT_OBJECT_0, "WaitForSingleObject error %u\n", GetLastError());
178     CloseHandle(hthread);
179 
180     type = GetObjectType(hgdiobj_event.hgdiobj2);
181     ok(type == OBJ_REGION, "GetObjectType returned %u\n", type);
182     bRet = DeleteObject(hgdiobj_event.hgdiobj2);
183     ok(bRet, "DeleteObject error %u\n", GetLastError());
184 
185     CloseHandle(hgdiobj_event.stop_event);
186     CloseHandle(hgdiobj_event.ready_event);
187 }
188 
189 static void test_GetCurrentObject(void)
190 {
191     DWORD type;
192     HPEN hpen;
193     HBRUSH hbrush;
194     HPALETTE hpal;
195     HFONT hfont;
196     HBITMAP hbmp;
197     HRGN hrgn;
198     HDC hdc;
199     HCOLORSPACE hcs;
200     HGDIOBJ hobj;
201     LOGBRUSH lb;
202     LOGCOLORSPACEA lcs;
203 
204     hdc = CreateCompatibleDC(0);
205     assert(hdc != 0);
206 
207     type = GetObjectType(hdc);
208     ok(type == OBJ_MEMDC, "GetObjectType returned %u\n", type);
209 
210     hpen = CreatePen(PS_SOLID, 10, RGB(10, 20, 30));
211     assert(hpen != 0);
212     SelectObject(hdc, hpen);
213     hobj = GetCurrentObject(hdc, OBJ_PEN);
214     ok(hobj == hpen, "OBJ_PEN is wrong: %p\n", hobj);
215     hobj = GetCurrentObject(hdc, OBJ_EXTPEN);
216     ok(hobj == hpen, "OBJ_EXTPEN is wrong: %p\n", hobj);
217 
218     hbrush = CreateSolidBrush(RGB(10, 20, 30));
219     assert(hbrush != 0);
220     SelectObject(hdc, hbrush);
221     hobj = GetCurrentObject(hdc, OBJ_BRUSH);
222     ok(hobj == hbrush, "OBJ_BRUSH is wrong: %p\n", hobj);
223 
224     hpal = CreateHalftonePalette(hdc);
225     assert(hpal != 0);
226     SelectPalette(hdc, hpal, FALSE);
227     hobj = GetCurrentObject(hdc, OBJ_PAL);
228     ok(hobj == hpal, "OBJ_PAL is wrong: %p\n", hobj);
229 
230     hfont = CreateFontA(10, 5, 0, 0, FW_DONTCARE, 0, 0, 0, ANSI_CHARSET,
231                         OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
232                         DEFAULT_PITCH, "MS Sans Serif");
233     assert(hfont != 0);
234     SelectObject(hdc, hfont);
235     hobj = GetCurrentObject(hdc, OBJ_FONT);
236     ok(hobj == hfont, "OBJ_FONT is wrong: %p\n", hobj);
237 
238     hbmp = CreateBitmap(100, 100, 1, 1, NULL);
239     assert(hbmp != 0);
240     SelectObject(hdc, hbmp);
241     hobj = GetCurrentObject(hdc, OBJ_BITMAP);
242     ok(hobj == hbmp, "OBJ_BITMAP is wrong: %p\n", hobj);
243 
244     assert(GetObjectA(hbrush, sizeof(lb), &lb) == sizeof(lb));
245     hpen = ExtCreatePen(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_SQUARE | PS_JOIN_BEVEL,
246                         10, &lb, 0, NULL);
247     assert(hpen != 0);
248     SelectObject(hdc, hpen);
249     hobj = GetCurrentObject(hdc, OBJ_PEN);
250     ok(hobj == hpen, "OBJ_PEN is wrong: %p\n", hobj);
251     hobj = GetCurrentObject(hdc, OBJ_EXTPEN);
252     ok(hobj == hpen, "OBJ_EXTPEN is wrong: %p\n", hobj);
253 
254     hcs = GetColorSpace(hdc);
255     if (hcs)
256     {
257         trace("current color space is not NULL\n");
258         ok(GetLogColorSpaceA(hcs, &lcs, sizeof(lcs)), "GetLogColorSpace failed\n");
259         hcs = CreateColorSpaceA(&lcs);
260         ok(hcs != 0, "CreateColorSpace failed\n");
261         SelectObject(hdc, hcs);
262         hobj = GetCurrentObject(hdc, OBJ_COLORSPACE);
263         ok(hobj == hcs, "OBJ_COLORSPACE is wrong: %p\n", hobj);
264     }
265 
266     hrgn = CreateRectRgn(1, 1, 100, 100);
267     assert(hrgn != 0);
268     SelectObject(hdc, hrgn);
269     hobj = GetCurrentObject(hdc, OBJ_REGION);
270     ok(!hobj, "OBJ_REGION is wrong: %p\n", hobj);
271 
272     DeleteDC(hdc);
273 }
274 
275 static void test_region(void)
276 {
277     HRGN hrgn = CreateRectRgn(10, 10, 20, 20);
278     RECT rc = { 5, 5, 15, 15 };
279     BOOL ret = RectInRegion( hrgn, &rc);
280     ok( ret, "RectInRegion should return TRUE\n");
281     /* swap left and right */
282     SetRect( &rc, 15, 5, 5, 15 );
283     ret = RectInRegion( hrgn, &rc);
284     ok( ret, "RectInRegion should return TRUE\n");
285     /* swap top and bottom */
286     SetRect( &rc, 5, 15, 15, 5 );
287     ret = RectInRegion( hrgn, &rc);
288     ok( ret, "RectInRegion should return TRUE\n");
289     /* swap both */
290     SetRect( &rc, 15, 15, 5, 5 );
291     ret = RectInRegion( hrgn, &rc);
292     ok( ret, "RectInRegion should return TRUE\n");
293     DeleteObject(hrgn);
294     /* swap left and right in the region */
295     hrgn = CreateRectRgn(20, 10, 10, 20);
296     SetRect( &rc, 5, 5, 15, 15 );
297     ret = RectInRegion( hrgn, &rc);
298     ok( ret, "RectInRegion should return TRUE\n");
299     /* swap left and right */
300     SetRect( &rc, 15, 5, 5, 15 );
301     ret = RectInRegion( hrgn, &rc);
302     ok( ret, "RectInRegion should return TRUE\n");
303     /* swap top and bottom */
304     SetRect( &rc, 5, 15, 15, 5 );
305     ret = RectInRegion( hrgn, &rc);
306     ok( ret, "RectInRegion should return TRUE\n");
307     /* swap both */
308     SetRect( &rc, 15, 15, 5, 5 );
309     ret = RectInRegion( hrgn, &rc);
310     ok( ret, "RectInRegion should return TRUE\n");
311     DeleteObject(hrgn);
312 }
313 
314 static void test_handles_on_win64(void)
315 {
316     int i;
317     BOOL ret;
318     DWORD type;
319     HRGN hrgn, hrgn_test;
320 
321     static const struct
322     {
323         ULONG high;
324         ULONG low;
325         BOOL  ret;
326     } cases[] =
327     {
328         { 0x00000000, 0x00000000, TRUE  },
329         { 0x00000000, 0x0000ffe0, FALSE }, /* just over MAX_LARGE_HANDLES */
330         { 0x00000000, 0x0000ffb0, FALSE }, /* just under MAX_LARGE_HANDLES */
331         { 0xffffffff, 0xffff0000, FALSE },
332         { 0xffffffff, 0x00000000, TRUE  },
333         { 0xdeadbeef, 0x00000000, TRUE  },
334         { 0xcccccccc, 0xcccccccc, FALSE }
335     };
336 
337     if (sizeof(void*) != 8)
338         return;
339 
340     for (i = 0; i < sizeof(cases)/sizeof(cases[0]); i++)
341     {
342         hrgn = CreateRectRgn(10, 10, 20, 20);
343         hrgn_test = (HRGN)(ULONG_PTR)((ULONG_PTR)hrgn | ((ULONGLONG)cases[i].high << 32) | cases[i].low);
344         type = GetObjectType( hrgn_test );
345         if (cases[i].ret)
346             ok( type == OBJ_REGION, "wrong type %u\n", type );
347         else
348             ok( type == 0, "wrong type %u\n", type );
349         ret = DeleteObject(hrgn_test);
350         ok( cases[i].ret == ret, "DeleteObject should return %s (%p)\n",
351             cases[i].ret ? "TRUE" : "FALSE", hrgn_test);
352         /* actually free it if above is expected to fail */
353         if (!ret) DeleteObject(hrgn);
354     }
355 }
356 
357 START_TEST(gdiobj)
358 {
359     test_gdi_objects();
360     test_thread_objects();
361     test_GetCurrentObject();
362     test_region();
363     test_handles_on_win64();
364 }
365