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