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