729a96d40b7a421c1eb140be1aea3a5523064e87
[reactos.git] / modules / rostests / winetests / gdi32 / gdiobj.c
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 }