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