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