dsound: Always enumerate the default device first.
[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         ok(ext_pen.elp.elpPenStyle == pen[i].style, "expected %x, got %x\n", pen[i].style, ext_pen.elp.elpPenStyle);
315         ok(ext_pen.elp.elpWidth == 1, "expected 1, got %x\n", ext_pen.elp.elpWidth);
316         ok(ext_pen.elp.elpColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, ext_pen.elp.elpColor);
317         ok(ext_pen.elp.elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %x\n", ext_pen.elp.elpBrushStyle);
318
319         DeleteObject(hpen);
320
321 test_geometric_pens:
322         /********************** geometric pens **********************/
323         lb.lbStyle = BS_SOLID;
324         lb.lbColor = pen[i].color;
325         lb.lbHatch = HS_CROSS; /* just in case */
326         SetLastError(0xdeadbeef);
327         hpen = ExtCreatePen(PS_GEOMETRIC | pen[i].style, pen[i].width, &lb, 2, user_style);
328         if (pen[i].style != PS_USERSTYLE)
329         {
330             ok(hpen == 0, "ExtCreatePen should fail\n");
331             SetLastError(0xdeadbeef);
332             hpen = ExtCreatePen(PS_GEOMETRIC | pen[i].style, pen[i].width, &lb, 0, NULL);
333         }
334         if (pen[i].style == PS_ALTERNATE)
335         {
336             /* This style is applicable only for cosmetic pens */
337             ok(hpen == 0, "ExtCreatePen should fail\n");
338             continue;
339         }
340         ok(hpen != 0, "ExtCreatePen error %d\n", GetLastError());
341
342         obj_type = GetObjectType(hpen);
343         /* for some reason XP differentiates PS_NULL here */
344         if (pen[i].style == PS_NULL)
345             ok(obj_type == OBJ_PEN, "wrong object type %u\n", obj_type);
346         else
347             ok(obj_type == OBJ_EXTPEN, "wrong object type %u\n", obj_type);
348
349         /* check what's the real size of the object */
350         size = GetObject(hpen, 0, NULL);
351         switch (pen[i].style)
352         {
353         case PS_NULL:
354             ok(size == sizeof(LOGPEN),
355                "GetObject returned %d, error %d\n", size, GetLastError());
356             break;
357
358         case PS_USERSTYLE:
359             ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry) + sizeof(user_style),
360                "GetObject returned %d, error %d\n", size, GetLastError());
361             break;
362
363         default:
364             ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry),
365                "GetObject returned %d, error %d\n", size, GetLastError());
366             break;
367         }
368
369         /* ask for truncated data */
370         memset(&lp, 0xb0, sizeof(lp));
371         SetLastError(0xdeadbeef);
372         size = GetObject(hpen, sizeof(lp.lopnStyle), &lp);
373         ok(!size, "GetObject should fail: size %d, error %d\n", size, GetLastError());
374
375         memset(&lp, 0xb0, sizeof(lp));
376         SetLastError(0xdeadbeef);
377         size = GetObject(hpen, sizeof(lp), &lp);
378         /* for some reason XP differentiates PS_NULL here */
379         if (pen[i].style == PS_NULL)
380         {
381             ok(size == sizeof(LOGPEN), "GetObject returned %d, error %d\n", size, GetLastError());
382             ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
383             ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
384             ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
385             ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
386         }
387         else
388             /* XP doesn't set last error here */
389             ok(!size /*&& GetLastError() == ERROR_INVALID_PARAMETER*/,
390                "GetObject should fail: size %d, error %d\n", size, GetLastError());
391
392         memset(&ext_pen, 0xb0, sizeof(ext_pen));
393         SetLastError(0xdeadbeef);
394         /* buffer is too small for user styles */
395         size = GetObject(hpen, sizeof(elp), &ext_pen.elp);
396         switch (pen[i].style)
397         {
398         case PS_NULL:
399             ok(size == sizeof(EXTLOGPEN),
400                 "GetObject returned %d, error %d\n", size, GetLastError());
401             ok(ext_pen.elp.elpHatch == 0, "expected 0, got %p\n", (void *)ext_pen.elp.elpHatch);
402             ok(ext_pen.elp.elpNumEntries == 0, "expected 0, got %x\n", ext_pen.elp.elpNumEntries);
403
404             /* for PS_NULL it also works this way */
405             SetLastError(0xdeadbeef);
406             size = GetObject(hpen, sizeof(ext_pen), &lp);
407             ok(size == sizeof(LOGPEN),
408                 "GetObject returned %d, error %d\n", size, GetLastError());
409             ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
410             ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
411             ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
412             ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
413             break;
414
415         case PS_USERSTYLE:
416             ok(!size /*&& GetLastError() == ERROR_INVALID_PARAMETER*/,
417                "GetObject should fail: size %d, error %d\n", size, GetLastError());
418             size = GetObject(hpen, sizeof(ext_pen), &ext_pen.elp);
419             ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry) + sizeof(user_style),
420                "GetObject returned %d, error %d\n", size, GetLastError());
421             ok(ext_pen.elp.elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen.elp.elpHatch);
422             ok(ext_pen.elp.elpNumEntries == 2, "expected 0, got %x\n", ext_pen.elp.elpNumEntries);
423             ok(ext_pen.elp.elpStyleEntry[0] == 0xabc, "expected 0xabc, got %x\n", ext_pen.elp.elpStyleEntry[0]);
424             ok(ext_pen.elp.elpStyleEntry[1] == 0xdef, "expected 0xdef, got %x\n", ext_pen.elp.elpStyleEntry[1]);
425             break;
426
427         default:
428             ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry),
429                "GetObject returned %d, error %d\n", size, GetLastError());
430             ok(ext_pen.elp.elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen.elp.elpHatch);
431             ok(ext_pen.elp.elpNumEntries == 0, "expected 0, got %x\n", ext_pen.elp.elpNumEntries);
432             break;
433         }
434
435         /* for some reason XP differentiates PS_NULL here */
436         if (pen[i].style == PS_NULL)
437             ok(ext_pen.elp.elpPenStyle == pen[i].ret_style, "expected %x, got %x\n", pen[i].ret_style, ext_pen.elp.elpPenStyle);
438         else
439         {
440             ok(ext_pen.elp.elpPenStyle == (PS_GEOMETRIC | pen[i].style), "expected %x, got %x\n", PS_GEOMETRIC | pen[i].style, ext_pen.elp.elpPenStyle);
441         }
442
443         if (pen[i].style == PS_NULL)
444             ok(ext_pen.elp.elpWidth == 0, "expected 0, got %x\n", ext_pen.elp.elpWidth);
445         else
446             ok(ext_pen.elp.elpWidth == pen[i].ret_width, "expected %u, got %x\n", pen[i].ret_width, ext_pen.elp.elpWidth);
447         ok(ext_pen.elp.elpColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, ext_pen.elp.elpColor);
448         ok(ext_pen.elp.elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %x\n", ext_pen.elp.elpBrushStyle);
449
450         DeleteObject(hpen);
451     }
452 }
453
454 static unsigned int atoi2(const char *s)
455 {
456     unsigned int ret = 0;
457     while(*s) ret = (ret << 1) | (*s++ == '1');
458     return ret;
459 }
460
461 #define TEST_LINE(x1, x2, z) \
462     { int buf = 0; \
463       SetBitmapBits(bmp, sizeof(buf), &buf); \
464       MoveToEx(hdc, x1, 0, NULL); \
465       LineTo(hdc, x2, 0); \
466       GetBitmapBits(bmp, sizeof(buf), &buf); \
467       expect(atoi2(z), buf); }
468
469 static void test_ps_alternate(void)
470 {
471     HDC hdc;
472     HBITMAP bmp;
473     HPEN pen;
474     LOGBRUSH lb;
475     INT iRet;
476     HGDIOBJ hRet;
477
478     lb.lbStyle = BS_SOLID;
479     lb.lbColor = RGB(0xff,0xff,0xff);
480
481     SetLastError(0xdeadbeef);
482     pen = ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, NULL);
483     if(pen == NULL && GetLastError() == 0xdeadbeef) {
484         skip("looks like 9x, skipping PS_ALTERNATE tests\n");
485         return;
486     }
487     ok(pen != NULL, "gle=%d\n", GetLastError());
488     hdc = CreateCompatibleDC(NULL);
489     ok(hdc != NULL, "gle=%d\n", GetLastError());
490     bmp = CreateBitmap(8, 1, 1, 1, NULL);
491     ok(bmp != NULL, "gle=%d\n", GetLastError());
492     hRet = SelectObject(hdc, bmp);
493     ok(hRet != NULL, "gle=%d\n", GetLastError());
494     hRet = SelectObject(hdc, pen);
495     ok(hRet != NULL, "gle=%d\n", GetLastError());
496     iRet = SetBkMode(hdc, TRANSPARENT);
497     ok(iRet, "gle=%d\n", GetLastError());
498
499     TEST_LINE(0, 1, "10000000")
500     TEST_LINE(0, 2, "10000000")
501     TEST_LINE(0, 3, "10100000")
502     TEST_LINE(0, 4, "10100000")
503     TEST_LINE(1, 4, "01010000")
504     TEST_LINE(1, 5, "01010000")
505     TEST_LINE(4, 8, "00001010")
506
507     DeleteObject(pen);
508     DeleteObject(bmp);
509     DeleteDC(hdc);
510 }
511
512 static void test_ps_userstyle(void)
513 {
514     static DWORD style[17] = {0, 2, 0, 4, 5, 0, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 17};
515     static DWORD bad_style[5] = {0, 0, 0, 0, 0};
516     static DWORD bad_style2[5] = {4, 7, 8, 3, -1};
517
518     LOGBRUSH lb;
519     HPEN pen;
520     INT size, i;
521
522     struct
523     {
524         EXTLOGPEN elp;
525         DWORD style_data[15];
526     } ext_pen;
527
528     lb.lbColor = 0x00ff0000;
529     lb.lbStyle = BS_SOLID;
530     lb.lbHatch = 0;
531
532     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 3, NULL);
533     ok(pen == 0, "ExtCreatePen should fail\n");
534     if (pen == 0 && GetLastError() == 0xdeadbeef)
535     {
536         win_skip("Looks like 9x, skipping PS_USERSTYLE tests\n");
537         return;
538     }
539     expect(ERROR_INVALID_PARAMETER, GetLastError());
540     DeleteObject(pen);
541     SetLastError(0xdeadbeef);
542
543     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 0, style);
544     ok(pen == 0, "ExtCreatePen should fail\n");
545     expect2(0xdeadbeef, ERROR_INVALID_PARAMETER, GetLastError());
546     DeleteObject(pen);
547     SetLastError(0xdeadbeef);
548
549     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 17, style);
550     ok(pen == 0, "ExtCreatePen should fail\n");
551     expect(ERROR_INVALID_PARAMETER, GetLastError());
552     DeleteObject(pen);
553     SetLastError(0xdeadbeef);
554
555     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, -1, style);
556     ok(pen == 0, "ExtCreatePen should fail\n");
557     expect(0xdeadbeef, GetLastError());
558     DeleteObject(pen);
559     SetLastError(0xdeadbeef);
560
561     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 5, bad_style);
562     ok(pen == 0, "ExtCreatePen should fail\n");
563     expect(ERROR_INVALID_PARAMETER, GetLastError());
564     DeleteObject(pen);
565     SetLastError(0xdeadbeef);
566
567     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 5, bad_style2);
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, 16, style);
574     ok(pen != 0, "ExtCreatePen should not fail\n");
575
576     size = GetObject(pen, sizeof(ext_pen), &ext_pen);
577     expect(FIELD_OFFSET(EXTLOGPEN,elpStyleEntry[16]), size);
578
579     for(i = 0; i < 16; i++)
580         expect(style[i], ext_pen.elp.elpStyleEntry[i]);
581
582     DeleteObject(pen);
583 }
584
585 START_TEST(pen)
586 {
587     test_logpen();
588     test_ps_alternate();
589     test_ps_userstyle();
590 }