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