1 /* 2 * Unit test suite for pens 3 * 4 * Copyright 2006 Dmitry Timoshkov 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include <stdarg.h> 22 23 #include "windef.h" 24 #include "winbase.h" 25 #include "wingdi.h" 26 #include "winuser.h" 27 28 #include "wine/test.h" 29 30 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got) 31 #define expect2(expected, alt, got) ok(got == expected || got == alt, \ 32 "Expected %.8x or %.8x, got %.8x\n", expected, alt, got) 33 34 static void test_logpen(void) 35 { 36 static const struct 37 { 38 UINT style; 39 INT width; 40 COLORREF color; 41 UINT ret_style; 42 INT ret_width; 43 COLORREF ret_color; 44 } pen[] = { 45 { PS_SOLID, -123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) }, 46 { PS_SOLID, 0, RGB(0x12,0x34,0x56), PS_SOLID, 0, RGB(0x12,0x34,0x56) }, 47 { PS_SOLID, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) }, 48 { PS_DASH, 123, RGB(0x12,0x34,0x56), PS_DASH, 123, RGB(0x12,0x34,0x56) }, 49 { PS_DOT, 123, RGB(0x12,0x34,0x56), PS_DOT, 123, RGB(0x12,0x34,0x56) }, 50 { PS_DASHDOT, 123, RGB(0x12,0x34,0x56), PS_DASHDOT, 123, RGB(0x12,0x34,0x56) }, 51 { PS_DASHDOTDOT, 123, RGB(0x12,0x34,0x56), PS_DASHDOTDOT, 123, RGB(0x12,0x34,0x56) }, 52 { PS_NULL, -123, RGB(0x12,0x34,0x56), PS_NULL, 1, 0 }, 53 { PS_NULL, 123, RGB(0x12,0x34,0x56), PS_NULL, 1, 0 }, 54 { PS_INSIDEFRAME, 123, RGB(0x12,0x34,0x56), PS_INSIDEFRAME, 123, RGB(0x12,0x34,0x56) }, 55 { PS_USERSTYLE, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) }, 56 { PS_ALTERNATE, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) }, 57 { 9, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) }, 58 { 10, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) }, 59 { 11, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) }, 60 { 13, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) }, 61 { 14, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) }, 62 { 15, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) }, 63 }; 64 INT i, size; 65 HPEN hpen; 66 LOGPEN lp; 67 EXTLOGPEN elp; 68 LOGBRUSH lb; 69 DWORD_PTR unset_hatch; 70 DWORD obj_type, user_style[2] = { 0xabc, 0xdef }; 71 char elp_buffer[128]; 72 EXTLOGPEN *ext_pen = (EXTLOGPEN *)elp_buffer; 73 DWORD *ext_style = ext_pen->elpStyleEntry; 74 75 for (i = 0; i < sizeof(pen)/sizeof(pen[0]); i++) 76 { 77 trace("%d: testing style %u\n", i, pen[i].style); 78 79 /********************** cosmetic pens **********************/ 80 /* CreatePenIndirect behaviour */ 81 lp.lopnStyle = pen[i].style, 82 lp.lopnWidth.x = pen[i].width; 83 lp.lopnWidth.y = 11; /* just in case */ 84 lp.lopnColor = pen[i].color; 85 SetLastError(0xdeadbeef); 86 hpen = CreatePenIndirect(&lp); 87 if(hpen == 0 && GetLastError() == ERROR_INVALID_PARAMETER) 88 { 89 win_skip("No support for pen style %u (%d)\n", pen[i].style, i); 90 continue; 91 } 92 93 obj_type = GetObjectType(hpen); 94 ok(obj_type == OBJ_PEN, "wrong object type %u\n", obj_type); 95 96 memset(&lp, 0xb0, sizeof(lp)); 97 SetLastError(0xdeadbeef); 98 size = GetObjectW(hpen, sizeof(lp), &lp); 99 ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError()); 100 101 ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle); 102 ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x); 103 ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y); 104 ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor); 105 106 DeleteObject(hpen); 107 108 /* CreatePen behaviour */ 109 SetLastError(0xdeadbeef); 110 hpen = CreatePen(pen[i].style, pen[i].width, pen[i].color); 111 ok(hpen != 0, "CreatePen error %d\n", GetLastError()); 112 113 obj_type = GetObjectType(hpen); 114 ok(obj_type == OBJ_PEN, "wrong object type %u\n", obj_type); 115 116 /* check what's the real size of the object */ 117 size = GetObjectW(hpen, 0, NULL); 118 ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError()); 119 120 /* ask for truncated data */ 121 memset(&lp, 0xb0, sizeof(lp)); 122 SetLastError(0xdeadbeef); 123 size = GetObjectW(hpen, sizeof(lp.lopnStyle), &lp); 124 ok(!size, "GetObject should fail: size %d, error %d\n", size, GetLastError()); 125 126 /* see how larger buffer sizes are handled */ 127 memset(&lp, 0xb0, sizeof(lp)); 128 SetLastError(0xdeadbeef); 129 size = GetObjectW(hpen, sizeof(lp) * 4, &lp); 130 ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError()); 131 132 /* see how larger buffer sizes are handled */ 133 memset(&elp, 0xb0, sizeof(elp)); 134 SetLastError(0xdeadbeef); 135 size = GetObjectW(hpen, sizeof(elp) * 2, &elp); 136 ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError()); 137 138 memset(&lp, 0xb0, sizeof(lp)); 139 SetLastError(0xdeadbeef); 140 size = GetObjectW(hpen, sizeof(lp), &lp); 141 ok(size == sizeof(lp), "GetObject returned %d, error %d\n", size, GetLastError()); 142 143 ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle); 144 ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x); 145 ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y); 146 ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor); 147 148 memset(&elp, 0xb0, sizeof(elp)); 149 SetLastError(0xdeadbeef); 150 size = GetObjectW(hpen, sizeof(elp), &elp); 151 152 /* for some reason XP differentiates PS_NULL here */ 153 if (pen[i].style == PS_NULL) 154 { 155 ok(hpen == GetStockObject(NULL_PEN), "hpen should be a stock NULL_PEN\n"); 156 ok(size == offsetof(EXTLOGPEN, elpStyleEntry[1]), "GetObject returned %d, error %d\n", 157 size, GetLastError()); 158 ok(elp.elpPenStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, elp.elpPenStyle); 159 ok(elp.elpWidth == 0, "expected 0, got %u\n", elp.elpWidth); 160 ok(elp.elpColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, elp.elpColor); 161 ok(elp.elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %u\n", elp.elpBrushStyle); 162 ok(elp.elpHatch == 0, "expected 0, got %p\n", (void *)elp.elpHatch); 163 ok(elp.elpNumEntries == 0, "expected 0, got %x\n", elp.elpNumEntries); 164 } 165 else 166 { 167 ok(size == sizeof(LOGPEN), "GetObject returned %d, error %d\n", size, GetLastError()); 168 memcpy(&lp, &elp, sizeof(lp)); 169 ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle); 170 ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x); 171 ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y); 172 ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor); 173 } 174 175 DeleteObject(hpen); 176 177 /********** cosmetic pens created by ExtCreatePen ***********/ 178 lb.lbStyle = BS_SOLID; 179 lb.lbColor = pen[i].color; 180 lb.lbHatch = HS_CROSS; /* just in case */ 181 SetLastError(0xdeadbeef); 182 hpen = ExtCreatePen(pen[i].style, pen[i].width, &lb, 2, user_style); 183 if (pen[i].style != PS_USERSTYLE) 184 { 185 ok(hpen == 0, "ExtCreatePen should fail\n"); 186 ok(GetLastError() == ERROR_INVALID_PARAMETER, 187 "wrong last error value %d\n", GetLastError()); 188 SetLastError(0xdeadbeef); 189 hpen = ExtCreatePen(pen[i].style, pen[i].width, &lb, 0, NULL); 190 if (pen[i].style != PS_NULL) 191 { 192 ok(hpen == 0, "ExtCreatePen with width != 1 should fail\n"); 193 ok(GetLastError() == ERROR_INVALID_PARAMETER, 194 "wrong last error value %d\n", GetLastError()); 195 196 SetLastError(0xdeadbeef); 197 hpen = ExtCreatePen(pen[i].style, 1, &lb, 0, NULL); 198 } 199 } 200 else 201 { 202 ok(hpen == 0, "ExtCreatePen with width != 1 should fail\n"); 203 ok(GetLastError() == ERROR_INVALID_PARAMETER, 204 "wrong last error value %d\n", GetLastError()); 205 SetLastError(0xdeadbeef); 206 hpen = ExtCreatePen(pen[i].style, 1, &lb, 2, user_style); 207 } 208 if (pen[i].style == PS_INSIDEFRAME) 209 { 210 /* This style is applicable only for geometric pens */ 211 ok(hpen == 0, "ExtCreatePen should fail\n"); 212 goto test_geometric_pens; 213 } 214 if (pen[i].style > PS_ALTERNATE) 215 { 216 ok(hpen == 0, "ExtCreatePen should fail\n"); 217 ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong last error value %d\n", GetLastError()); 218 goto test_geometric_pens; 219 } 220 ok(hpen != 0, "ExtCreatePen error %d\n", GetLastError()); 221 222 obj_type = GetObjectType(hpen); 223 /* for some reason XP differentiates PS_NULL here */ 224 if (pen[i].style == PS_NULL) 225 { 226 ok(obj_type == OBJ_PEN, "wrong object type %u\n", obj_type); 227 ok(hpen == GetStockObject(NULL_PEN), "hpen should be a stock NULL_PEN\n"); 228 } 229 else 230 ok(obj_type == OBJ_EXTPEN, "wrong object type %u\n", obj_type); 231 232 /* check what's the real size of the object */ 233 SetLastError(0xdeadbeef); 234 size = GetObjectW(hpen, 0, NULL); 235 switch (pen[i].style) 236 { 237 case PS_NULL: 238 ok(size == sizeof(LOGPEN), 239 "GetObject returned %d, error %d\n", size, GetLastError()); 240 break; 241 242 case PS_USERSTYLE: 243 ok(size == offsetof( EXTLOGPEN, elpStyleEntry[2] ), 244 "GetObject returned %d, error %d\n", size, GetLastError()); 245 break; 246 247 default: 248 ok(size == offsetof( EXTLOGPEN, elpStyleEntry ), 249 "GetObject returned %d, error %d\n", size, GetLastError()); 250 break; 251 } 252 253 /* ask for truncated data */ 254 memset(&elp, 0xb0, sizeof(elp)); 255 SetLastError(0xdeadbeef); 256 size = GetObjectW(hpen, sizeof(elp.elpPenStyle), &elp); 257 ok(!size, "GetObject should fail: size %d, error %d\n", size, GetLastError()); 258 259 /* see how larger buffer sizes are handled */ 260 memset(elp_buffer, 0xb0, sizeof(elp_buffer)); 261 SetLastError(0xdeadbeef); 262 size = GetObjectW(hpen, sizeof(elp_buffer), elp_buffer); 263 switch (pen[i].style) 264 { 265 case PS_NULL: 266 ok(size == sizeof(LOGPEN), 267 "GetObject returned %d, error %d\n", size, GetLastError()); 268 memcpy(&lp, ext_pen, sizeof(lp)); 269 ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle); 270 ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x); 271 ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y); 272 ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor); 273 274 /* for PS_NULL it also works this way */ 275 memset(&elp, 0xb0, sizeof(elp)); 276 memset(&unset_hatch, 0xb0, sizeof(unset_hatch)); 277 SetLastError(0xdeadbeef); 278 size = GetObjectW(hpen, sizeof(elp), &elp); 279 ok(size == offsetof(EXTLOGPEN, elpStyleEntry[1]), 280 "GetObject returned %d, error %d\n", size, GetLastError()); 281 ok(ext_pen->elpHatch == unset_hatch, "expected 0xb0b0b0b0, got %p\n", (void *)ext_pen->elpHatch); 282 ok(ext_pen->elpNumEntries == 0xb0b0b0b0, "expected 0xb0b0b0b0, got %x\n", ext_pen->elpNumEntries); 283 break; 284 285 case PS_USERSTYLE: 286 ok(size == offsetof( EXTLOGPEN, elpStyleEntry[2] ), 287 "GetObject returned %d, error %d\n", size, GetLastError()); 288 ok(ext_pen->elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen->elpHatch); 289 ok(ext_pen->elpNumEntries == 2, "expected 0, got %x\n", ext_pen->elpNumEntries); 290 ok(ext_style[0] == 0xabc, "expected 0xabc, got %x\n", ext_style[0]); 291 ok(ext_style[1] == 0xdef, "expected 0xdef, got %x\n", ext_style[1]); 292 break; 293 294 default: 295 ok(size == offsetof( EXTLOGPEN, elpStyleEntry ), 296 "GetObject returned %d, error %d\n", size, GetLastError()); 297 ok(ext_pen->elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen->elpHatch); 298 ok(ext_pen->elpNumEntries == 0, "expected 0, got %x\n", ext_pen->elpNumEntries); 299 break; 300 } 301 302 ok(ext_pen->elpPenStyle == pen[i].style, "expected %x, got %x\n", pen[i].style, ext_pen->elpPenStyle); 303 ok(ext_pen->elpWidth == 1, "expected 1, got %x\n", ext_pen->elpWidth); 304 ok(ext_pen->elpColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, ext_pen->elpColor); 305 ok(ext_pen->elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %x\n", ext_pen->elpBrushStyle); 306 307 DeleteObject(hpen); 308 309 test_geometric_pens: 310 /********************** geometric pens **********************/ 311 lb.lbStyle = BS_SOLID; 312 lb.lbColor = pen[i].color; 313 lb.lbHatch = HS_CROSS; /* just in case */ 314 SetLastError(0xdeadbeef); 315 hpen = ExtCreatePen(PS_GEOMETRIC | pen[i].style, pen[i].width, &lb, 2, user_style); 316 if (pen[i].style != PS_USERSTYLE) 317 { 318 ok(hpen == 0, "ExtCreatePen should fail\n"); 319 SetLastError(0xdeadbeef); 320 hpen = ExtCreatePen(PS_GEOMETRIC | pen[i].style, pen[i].width, &lb, 0, NULL); 321 } 322 if (pen[i].style == PS_ALTERNATE) 323 { 324 /* This style is applicable only for cosmetic pens */ 325 ok(hpen == 0, "ExtCreatePen should fail\n"); 326 continue; 327 } 328 if (pen[i].style > PS_ALTERNATE) 329 { 330 ok(hpen == 0, "ExtCreatePen should fail\n"); 331 ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong last error value %d\n", GetLastError()); 332 continue; 333 } 334 ok(hpen != 0, "ExtCreatePen error %d\n", GetLastError()); 335 336 obj_type = GetObjectType(hpen); 337 /* for some reason XP differentiates PS_NULL here */ 338 if (pen[i].style == PS_NULL) 339 ok(obj_type == OBJ_PEN, "wrong object type %u\n", obj_type); 340 else 341 ok(obj_type == OBJ_EXTPEN, "wrong object type %u\n", obj_type); 342 343 /* check what's the real size of the object */ 344 size = GetObjectW(hpen, 0, NULL); 345 switch (pen[i].style) 346 { 347 case PS_NULL: 348 ok(size == sizeof(LOGPEN), 349 "GetObject returned %d, error %d\n", size, GetLastError()); 350 break; 351 352 case PS_USERSTYLE: 353 ok(size == offsetof( EXTLOGPEN, elpStyleEntry[2] ), 354 "GetObject returned %d, error %d\n", size, GetLastError()); 355 break; 356 357 default: 358 ok(size == offsetof( EXTLOGPEN, elpStyleEntry ), 359 "GetObject returned %d, error %d\n", size, GetLastError()); 360 break; 361 } 362 363 /* ask for truncated data */ 364 memset(&lp, 0xb0, sizeof(lp)); 365 SetLastError(0xdeadbeef); 366 size = GetObjectW(hpen, sizeof(lp.lopnStyle), &lp); 367 ok(!size, "GetObject should fail: size %d, error %d\n", size, GetLastError()); 368 369 memset(&lp, 0xb0, sizeof(lp)); 370 SetLastError(0xdeadbeef); 371 size = GetObjectW(hpen, sizeof(lp), &lp); 372 /* for some reason XP differentiates PS_NULL here */ 373 if (pen[i].style == PS_NULL) 374 { 375 ok(size == sizeof(LOGPEN), "GetObject returned %d, error %d\n", size, GetLastError()); 376 ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle); 377 ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x); 378 ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y); 379 ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor); 380 } 381 else 382 /* XP doesn't set last error here */ 383 ok(!size /*&& GetLastError() == ERROR_INVALID_PARAMETER*/, 384 "GetObject should fail: size %d, error %d\n", size, GetLastError()); 385 386 memset(elp_buffer, 0xb0, sizeof(elp_buffer)); 387 SetLastError(0xdeadbeef); 388 /* buffer is too small for user styles */ 389 size = GetObjectW(hpen, offsetof(EXTLOGPEN, elpStyleEntry[1]), elp_buffer); 390 switch (pen[i].style) 391 { 392 case PS_NULL: 393 ok(size == offsetof(EXTLOGPEN, elpStyleEntry[1]), 394 "GetObject returned %d, error %d\n", size, GetLastError()); 395 ok(ext_pen->elpHatch == 0, "expected 0, got %p\n", (void *)ext_pen->elpHatch); 396 ok(ext_pen->elpNumEntries == 0, "expected 0, got %x\n", ext_pen->elpNumEntries); 397 398 /* for PS_NULL it also works this way */ 399 SetLastError(0xdeadbeef); 400 size = GetObjectW(hpen, sizeof(elp_buffer), &lp); 401 ok(size == sizeof(LOGPEN), 402 "GetObject returned %d, error %d\n", size, GetLastError()); 403 ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle); 404 ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x); 405 ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y); 406 ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor); 407 break; 408 409 case PS_USERSTYLE: 410 ok(!size /*&& GetLastError() == ERROR_INVALID_PARAMETER*/, 411 "GetObject should fail: size %d, error %d\n", size, GetLastError()); 412 size = GetObjectW(hpen, sizeof(elp_buffer), elp_buffer); 413 ok(size == offsetof( EXTLOGPEN, elpStyleEntry[2] ), 414 "GetObject returned %d, error %d\n", size, GetLastError()); 415 ok(ext_pen->elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen->elpHatch); 416 ok(ext_pen->elpNumEntries == 2, "expected 0, got %x\n", ext_pen->elpNumEntries); 417 ok(ext_style[0] == 0xabc, "expected 0xabc, got %x\n", ext_style[0]); 418 ok(ext_style[1] == 0xdef, "expected 0xdef, got %x\n", ext_style[1]); 419 break; 420 421 default: 422 ok(size == offsetof( EXTLOGPEN, elpStyleEntry ), 423 "GetObject returned %d, error %d\n", size, GetLastError()); 424 ok(ext_pen->elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen->elpHatch); 425 ok(ext_pen->elpNumEntries == 0, "expected 0, got %x\n", ext_pen->elpNumEntries); 426 break; 427 } 428 429 /* for some reason XP differentiates PS_NULL here */ 430 if (pen[i].style == PS_NULL) 431 ok(ext_pen->elpPenStyle == pen[i].ret_style, "expected %x, got %x\n", pen[i].ret_style, ext_pen->elpPenStyle); 432 else 433 { 434 ok(ext_pen->elpPenStyle == (PS_GEOMETRIC | pen[i].style), "expected %x, got %x\n", PS_GEOMETRIC | pen[i].style, ext_pen->elpPenStyle); 435 } 436 437 if (pen[i].style == PS_NULL) 438 ok(ext_pen->elpWidth == 0, "expected 0, got %x\n", ext_pen->elpWidth); 439 else 440 ok(ext_pen->elpWidth == pen[i].ret_width, "expected %u, got %x\n", pen[i].ret_width, ext_pen->elpWidth); 441 ok(ext_pen->elpColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, ext_pen->elpColor); 442 ok(ext_pen->elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %x\n", ext_pen->elpBrushStyle); 443 444 DeleteObject(hpen); 445 } 446 } 447 448 static unsigned int atoi2(const char *s) 449 { 450 unsigned int ret = 0; 451 while(*s) ret = (ret << 1) | (*s++ == '1'); 452 return ret; 453 } 454 455 #define TEST_LINE(x1, x2, z) \ 456 { int buf = 0; \ 457 SetBitmapBits(bmp, sizeof(buf), &buf); \ 458 MoveToEx(hdc, x1, 0, NULL); \ 459 LineTo(hdc, x2, 0); \ 460 GetBitmapBits(bmp, sizeof(buf), &buf); \ 461 expect(atoi2(z), buf); } 462 463 static void test_ps_alternate(void) 464 { 465 HDC hdc; 466 HBITMAP bmp; 467 HPEN pen; 468 LOGBRUSH lb; 469 INT iRet; 470 HGDIOBJ hRet; 471 472 lb.lbStyle = BS_SOLID; 473 lb.lbColor = RGB(0xff,0xff,0xff); 474 475 SetLastError(0xdeadbeef); 476 pen = ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, NULL); 477 if(pen == NULL && GetLastError() == 0xdeadbeef) { 478 skip("looks like 9x, skipping PS_ALTERNATE tests\n"); 479 return; 480 } 481 ok(pen != NULL, "gle=%d\n", GetLastError()); 482 hdc = CreateCompatibleDC(NULL); 483 ok(hdc != NULL, "gle=%d\n", GetLastError()); 484 bmp = CreateBitmap(8, 1, 1, 1, NULL); 485 ok(bmp != NULL, "gle=%d\n", GetLastError()); 486 hRet = SelectObject(hdc, bmp); 487 ok(hRet != NULL, "gle=%d\n", GetLastError()); 488 hRet = SelectObject(hdc, pen); 489 ok(hRet != NULL, "gle=%d\n", GetLastError()); 490 iRet = SetBkMode(hdc, TRANSPARENT); 491 ok(iRet, "gle=%d\n", GetLastError()); 492 493 TEST_LINE(0, 1, "10000000") 494 TEST_LINE(0, 2, "10000000") 495 TEST_LINE(0, 3, "10100000") 496 TEST_LINE(0, 4, "10100000") 497 TEST_LINE(1, 4, "01010000") 498 TEST_LINE(1, 5, "01010000") 499 TEST_LINE(4, 8, "00001010") 500 501 DeleteObject(pen); 502 DeleteObject(bmp); 503 DeleteDC(hdc); 504 } 505 506 static void test_ps_userstyle(void) 507 { 508 static DWORD style[17] = {0, 2, 0, 4, 5, 0, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 17}; 509 static DWORD bad_style[5] = {0, 0, 0, 0, 0}; 510 static DWORD bad_style2[5] = {4, 7, 8, 3, -1}; 511 512 LOGBRUSH lb; 513 HPEN pen; 514 INT size, i; 515 char buffer[offsetof(EXTLOGPEN, elpStyleEntry) + 16 * sizeof(DWORD)]; 516 EXTLOGPEN *ext_pen = (EXTLOGPEN *)buffer; 517 518 lb.lbColor = 0x00ff0000; 519 lb.lbStyle = BS_SOLID; 520 lb.lbHatch = 0; 521 522 pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 3, NULL); 523 ok(pen == 0, "ExtCreatePen should fail\n"); 524 expect(ERROR_INVALID_PARAMETER, GetLastError()); 525 DeleteObject(pen); 526 SetLastError(0xdeadbeef); 527 528 pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 0, style); 529 ok(pen == 0, "ExtCreatePen should fail\n"); 530 expect2(0xdeadbeef, ERROR_INVALID_PARAMETER, GetLastError()); 531 DeleteObject(pen); 532 SetLastError(0xdeadbeef); 533 534 pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 17, style); 535 ok(pen == 0, "ExtCreatePen should fail\n"); 536 expect(ERROR_INVALID_PARAMETER, GetLastError()); 537 DeleteObject(pen); 538 SetLastError(0xdeadbeef); 539 540 pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, -1, style); 541 ok(pen == 0, "ExtCreatePen should fail\n"); 542 expect(0xdeadbeef, GetLastError()); 543 DeleteObject(pen); 544 SetLastError(0xdeadbeef); 545 546 pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 5, bad_style); 547 ok(pen == 0, "ExtCreatePen should fail\n"); 548 expect(ERROR_INVALID_PARAMETER, GetLastError()); 549 DeleteObject(pen); 550 SetLastError(0xdeadbeef); 551 552 pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 5, bad_style2); 553 ok(pen == 0, "ExtCreatePen should fail\n"); 554 expect(ERROR_INVALID_PARAMETER, GetLastError()); 555 DeleteObject(pen); 556 SetLastError(0xdeadbeef); 557 558 pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 16, style); 559 ok(pen != 0, "ExtCreatePen should not fail\n"); 560 561 size = GetObjectW(pen, sizeof(buffer), ext_pen); 562 ok(size == offsetof(EXTLOGPEN, elpStyleEntry[16]), "wrong size %d\n", size); 563 564 for(i = 0; i < 16; i++) 565 expect(style[i], ext_pen->elpStyleEntry[i]); 566 567 DeleteObject(pen); 568 } 569 570 static void test_brush_pens(void) 571 { 572 char buffer[offsetof(EXTLOGPEN, elpStyleEntry) + 16 * sizeof(DWORD)]; 573 EXTLOGPEN *elp = (EXTLOGPEN *)buffer; 574 LOGBRUSH lb; 575 HPEN pen = 0; 576 DWORD size; 577 HBITMAP bmp = CreateBitmap( 8, 8, 1, 1, NULL ); 578 BITMAPINFO *info; 579 HGLOBAL hmem; 580 581 hmem = GlobalAlloc( GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(*info) + 16 * 16 * 4 ); 582 info = GlobalLock( hmem ); 583 info->bmiHeader.biSize = sizeof(info->bmiHeader); 584 info->bmiHeader.biWidth = 16; 585 info->bmiHeader.biHeight = 16; 586 info->bmiHeader.biPlanes = 1; 587 info->bmiHeader.biBitCount = 32; 588 info->bmiHeader.biCompression = BI_RGB; 589 590 for (lb.lbStyle = BS_SOLID; lb.lbStyle <= BS_MONOPATTERN + 1; lb.lbStyle++) 591 { 592 SetLastError( 0xdeadbeef ); 593 memset( buffer, 0xcc, sizeof(buffer) ); 594 trace( "testing brush style %u\n", lb.lbStyle ); 595 596 switch (lb.lbStyle) 597 { 598 case BS_SOLID: 599 case BS_HATCHED: 600 lb.lbColor = RGB(12,34,56); 601 lb.lbHatch = HS_CROSS; 602 pen = ExtCreatePen( PS_DOT | PS_GEOMETRIC, 3, &lb, 0, NULL ); 603 ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() ); 604 size = GetObjectW( pen, sizeof(buffer), elp ); 605 ok( size == offsetof( EXTLOGPEN, elpStyleEntry ), "wrong size %u\n", size ); 606 ok( elp->elpPenStyle == (PS_DOT | PS_GEOMETRIC), "wrong pen style %x\n", elp->elpPenStyle ); 607 ok( elp->elpBrushStyle == lb.lbStyle, "wrong brush style %x\n", elp->elpBrushStyle ); 608 ok( elp->elpColor == RGB(12,34,56), "wrong color %x\n", elp->elpColor ); 609 ok( elp->elpHatch == HS_CROSS, "wrong hatch %lx\n", elp->elpHatch ); 610 ok( elp->elpNumEntries == 0, "wrong entries %x\n", elp->elpNumEntries ); 611 break; 612 613 case BS_NULL: 614 pen = ExtCreatePen( PS_SOLID | PS_GEOMETRIC, 3, &lb, 0, NULL ); 615 ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() ); 616 size = GetObjectW( pen, sizeof(buffer), elp ); 617 ok( size == sizeof(LOGPEN), "wrong size %u\n", size ); 618 ok( ((LOGPEN *)elp)->lopnStyle == PS_NULL, 619 "wrong pen style %x\n", ((LOGPEN *)elp)->lopnStyle ); 620 ok( ((LOGPEN *)elp)->lopnColor == 0, 621 "wrong color %x\n", ((LOGPEN *)elp)->lopnColor ); 622 break; 623 624 case BS_PATTERN: 625 lb.lbColor = RGB(12,34,56); 626 lb.lbHatch = (ULONG_PTR)bmp; 627 pen = ExtCreatePen( PS_DOT | PS_GEOMETRIC, 3, &lb, 0, NULL ); 628 ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() ); 629 size = GetObjectW( pen, sizeof(buffer), elp ); 630 ok( size == offsetof( EXTLOGPEN, elpStyleEntry ), "wrong size %u\n", size ); 631 ok( elp->elpPenStyle == (PS_DOT | PS_GEOMETRIC), "wrong pen style %x\n", elp->elpPenStyle ); 632 ok( elp->elpBrushStyle == BS_PATTERN, "wrong brush style %x\n", elp->elpBrushStyle ); 633 ok( elp->elpColor == 0, "wrong color %x\n", elp->elpColor ); 634 ok( elp->elpHatch == (ULONG_PTR)bmp, "wrong hatch %lx/%p\n", elp->elpHatch, bmp ); 635 ok( elp->elpNumEntries == 0, "wrong entries %x\n", elp->elpNumEntries ); 636 break; 637 638 case BS_DIBPATTERN: 639 case BS_DIBPATTERNPT: 640 lb.lbColor = DIB_PAL_COLORS; 641 lb.lbHatch = lb.lbStyle == BS_DIBPATTERN ? (ULONG_PTR)hmem : (ULONG_PTR)info; 642 pen = ExtCreatePen( PS_DOT | PS_GEOMETRIC, 3, &lb, 0, NULL ); 643 ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() ); 644 size = GetObjectW( pen, sizeof(buffer), elp ); 645 ok( size == offsetof( EXTLOGPEN, elpStyleEntry ), "wrong size %u\n", size ); 646 ok( elp->elpPenStyle == (PS_DOT | PS_GEOMETRIC), "wrong pen style %x\n", elp->elpPenStyle ); 647 ok( elp->elpBrushStyle == BS_DIBPATTERNPT, "wrong brush style %x\n", elp->elpBrushStyle ); 648 ok( elp->elpColor == 0, "wrong color %x\n", elp->elpColor ); 649 ok( elp->elpHatch == lb.lbHatch || broken(elp->elpHatch != lb.lbHatch), /* <= w2k */ 650 "wrong hatch %lx/%lx\n", elp->elpHatch, lb.lbHatch ); 651 ok( elp->elpNumEntries == 0, "wrong entries %x\n", elp->elpNumEntries ); 652 break; 653 654 default: 655 pen = ExtCreatePen( PS_DOT | PS_GEOMETRIC, 3, &lb, 0, NULL ); 656 ok( !pen, "ExtCreatePen succeeded\n" ); 657 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); 658 break; 659 } 660 661 if (pen) DeleteObject( pen ); 662 else continue; 663 664 /* cosmetic pens require BS_SOLID */ 665 SetLastError( 0xdeadbeef ); 666 pen = ExtCreatePen( PS_DOT, 1, &lb, 0, NULL ); 667 if (lb.lbStyle == BS_SOLID) 668 { 669 ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() ); 670 size = GetObjectW( pen, sizeof(buffer), elp ); 671 ok( size == offsetof( EXTLOGPEN, elpStyleEntry ), "wrong size %u\n", size ); 672 ok( elp->elpPenStyle == PS_DOT, "wrong pen style %x\n", elp->elpPenStyle ); 673 ok( elp->elpBrushStyle == BS_SOLID, "wrong brush style %x\n", elp->elpBrushStyle ); 674 ok( elp->elpColor == RGB(12,34,56), "wrong color %x\n", elp->elpColor ); 675 ok( elp->elpHatch == HS_CROSS, "wrong hatch %lx\n", elp->elpHatch ); 676 DeleteObject( pen ); 677 } 678 else 679 { 680 ok( !pen, "ExtCreatePen succeeded\n" ); 681 ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() ); 682 } 683 } 684 685 GlobalUnlock( hmem ); 686 GlobalFree( hmem ); 687 DeleteObject( bmp ); 688 } 689 690 START_TEST(pen) 691 { 692 test_logpen(); 693 test_brush_pens(); 694 test_ps_alternate(); 695 test_ps_userstyle(); 696 } 697