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