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