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