xref: /reactos/modules/rostests/winetests/gdi32/pen.c (revision d5b576b2)
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 "precomp.h"
22 
23 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
24 #define expect2(expected, alt, got) ok(got == expected || got == alt, \
25                                        "Expected %.8x or %.8x, got %.8x\n", expected, alt, got)
26 
27 static void test_logpen(void)
28 {
29     static const struct
30     {
31         UINT style;
32         INT width;
33         COLORREF color;
34         UINT ret_style;
35         INT ret_width;
36         COLORREF ret_color;
37     } pen[] = {
38         { PS_SOLID, -123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) },
39         { PS_SOLID, 0, RGB(0x12,0x34,0x56), PS_SOLID, 0, RGB(0x12,0x34,0x56) },
40         { PS_SOLID, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) },
41         { PS_DASH, 123, RGB(0x12,0x34,0x56), PS_DASH, 123, RGB(0x12,0x34,0x56) },
42         { PS_DOT, 123, RGB(0x12,0x34,0x56), PS_DOT, 123, RGB(0x12,0x34,0x56) },
43         { PS_DASHDOT, 123, RGB(0x12,0x34,0x56), PS_DASHDOT, 123, RGB(0x12,0x34,0x56) },
44         { PS_DASHDOTDOT, 123, RGB(0x12,0x34,0x56), PS_DASHDOTDOT, 123, RGB(0x12,0x34,0x56) },
45         { PS_NULL, -123, RGB(0x12,0x34,0x56), PS_NULL, 1, 0 },
46         { PS_NULL, 123, RGB(0x12,0x34,0x56), PS_NULL, 1, 0 },
47         { PS_INSIDEFRAME, 123, RGB(0x12,0x34,0x56), PS_INSIDEFRAME, 123, RGB(0x12,0x34,0x56) },
48         { PS_USERSTYLE, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) },
49         { PS_ALTERNATE, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) },
50         {  9, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) },
51         { 10, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) },
52         { 11, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) },
53         { 13, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) },
54         { 14, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) },
55         { 15, 123, RGB(0x12,0x34,0x56), PS_SOLID, 123, RGB(0x12,0x34,0x56) },
56     };
57     INT i, size;
58     HPEN hpen;
59     LOGPEN lp;
60     EXTLOGPEN elp;
61     LOGBRUSH lb;
62     DWORD_PTR unset_hatch;
63     DWORD obj_type, user_style[2] = { 0xabc, 0xdef };
64     char elp_buffer[128];
65     EXTLOGPEN *ext_pen = (EXTLOGPEN *)elp_buffer;
66     DWORD *ext_style = ext_pen->elpStyleEntry;
67 
68     for (i = 0; i < sizeof(pen)/sizeof(pen[0]); i++)
69     {
70         trace("%d: testing style %u\n", i, pen[i].style);
71 
72         /********************** cosmetic pens **********************/
73         /* CreatePenIndirect behaviour */
74         lp.lopnStyle = pen[i].style,
75         lp.lopnWidth.x = pen[i].width;
76         lp.lopnWidth.y = 11; /* just in case */
77         lp.lopnColor = pen[i].color;
78         SetLastError(0xdeadbeef);
79         hpen = CreatePenIndirect(&lp);
80         if(hpen == 0 && GetLastError() == ERROR_INVALID_PARAMETER)
81         {
82             win_skip("No support for pen style %u (%d)\n", pen[i].style, i);
83             continue;
84         }
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 = GetObjectW(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 = GetObjectW(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 = GetObjectW(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 = GetObjectW(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 = GetObjectW(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 = GetObjectW(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 = GetObjectW(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 == offsetof(EXTLOGPEN, elpStyleEntry[1]), "GetObject returned %d, error %d\n",
150                 size, GetLastError());
151             ok(elp.elpPenStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, elp.elpPenStyle);
152             ok(elp.elpWidth == 0, "expected 0, got %u\n", elp.elpWidth);
153             ok(elp.elpColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, elp.elpColor);
154             ok(elp.elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %u\n", elp.elpBrushStyle);
155             ok(elp.elpHatch == 0, "expected 0, got %p\n", (void *)elp.elpHatch);
156             ok(elp.elpNumEntries == 0, "expected 0, got %x\n", elp.elpNumEntries);
157         }
158         else
159         {
160             ok(size == sizeof(LOGPEN), "GetObject returned %d, error %d\n", size, GetLastError());
161             memcpy(&lp, &elp, sizeof(lp));
162             ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
163             ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
164             ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
165             ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
166         }
167 
168         DeleteObject(hpen);
169 
170         /********** cosmetic pens created by ExtCreatePen ***********/
171         lb.lbStyle = BS_SOLID;
172         lb.lbColor = pen[i].color;
173         lb.lbHatch = HS_CROSS; /* just in case */
174         SetLastError(0xdeadbeef);
175         hpen = ExtCreatePen(pen[i].style, pen[i].width, &lb, 2, user_style);
176         if (pen[i].style != PS_USERSTYLE)
177         {
178             ok(hpen == 0, "ExtCreatePen should fail\n");
179             ok(GetLastError() == ERROR_INVALID_PARAMETER,
180                "wrong last error value %d\n", GetLastError());
181             SetLastError(0xdeadbeef);
182             hpen = ExtCreatePen(pen[i].style, pen[i].width, &lb, 0, NULL);
183             if (pen[i].style != PS_NULL)
184             {
185                 ok(hpen == 0, "ExtCreatePen with width != 1 should fail\n");
186                 ok(GetLastError() == ERROR_INVALID_PARAMETER,
187                    "wrong last error value %d\n", GetLastError());
188 
189                 SetLastError(0xdeadbeef);
190                 hpen = ExtCreatePen(pen[i].style, 1, &lb, 0, NULL);
191             }
192         }
193         else
194         {
195             ok(hpen == 0, "ExtCreatePen with width != 1 should fail\n");
196             ok(GetLastError() == ERROR_INVALID_PARAMETER,
197                "wrong last error value %d\n", GetLastError());
198             SetLastError(0xdeadbeef);
199             hpen = ExtCreatePen(pen[i].style, 1, &lb, 2, user_style);
200         }
201         if (pen[i].style == PS_INSIDEFRAME)
202         {
203             /* This style is applicable only for geometric pens */
204             ok(hpen == 0, "ExtCreatePen should fail\n");
205             goto test_geometric_pens;
206         }
207         if (pen[i].style > PS_ALTERNATE)
208         {
209             ok(hpen == 0, "ExtCreatePen should fail\n");
210             ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong last error value %d\n", GetLastError());
211             goto test_geometric_pens;
212         }
213         ok(hpen != 0, "ExtCreatePen error %d\n", GetLastError());
214 
215         obj_type = GetObjectType(hpen);
216         /* for some reason XP differentiates PS_NULL here */
217         if (pen[i].style == PS_NULL)
218         {
219             ok(obj_type == OBJ_PEN, "wrong object type %u\n", obj_type);
220             ok(hpen == GetStockObject(NULL_PEN), "hpen should be a stock NULL_PEN\n");
221         }
222         else
223             ok(obj_type == OBJ_EXTPEN, "wrong object type %u\n", obj_type);
224 
225         /* check what's the real size of the object */
226         SetLastError(0xdeadbeef);
227         size = GetObjectW(hpen, 0, NULL);
228         switch (pen[i].style)
229         {
230         case PS_NULL:
231             ok(size == sizeof(LOGPEN),
232                "GetObject returned %d, error %d\n", size, GetLastError());
233             break;
234 
235         case PS_USERSTYLE:
236             ok(size == offsetof( EXTLOGPEN, elpStyleEntry[2] ),
237                "GetObject returned %d, error %d\n", size, GetLastError());
238             break;
239 
240         default:
241             ok(size == offsetof( EXTLOGPEN, elpStyleEntry ),
242                "GetObject returned %d, error %d\n", size, GetLastError());
243             break;
244         }
245 
246         /* ask for truncated data */
247         memset(&elp, 0xb0, sizeof(elp));
248         SetLastError(0xdeadbeef);
249         size = GetObjectW(hpen, sizeof(elp.elpPenStyle), &elp);
250         ok(!size, "GetObject should fail: size %d, error %d\n", size, GetLastError());
251 
252         /* see how larger buffer sizes are handled */
253         memset(elp_buffer, 0xb0, sizeof(elp_buffer));
254         SetLastError(0xdeadbeef);
255         size = GetObjectW(hpen, sizeof(elp_buffer), elp_buffer);
256         switch (pen[i].style)
257         {
258         case PS_NULL:
259             ok(size == sizeof(LOGPEN),
260                "GetObject returned %d, error %d\n", size, GetLastError());
261             memcpy(&lp, ext_pen, sizeof(lp));
262             ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
263             ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
264             ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
265             ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
266 
267             /* for PS_NULL it also works this way */
268             memset(&elp, 0xb0, sizeof(elp));
269             memset(&unset_hatch, 0xb0, sizeof(unset_hatch));
270             SetLastError(0xdeadbeef);
271             size = GetObjectW(hpen, sizeof(elp), &elp);
272             ok(size == offsetof(EXTLOGPEN, elpStyleEntry[1]),
273                 "GetObject returned %d, error %d\n", size, GetLastError());
274             ok(ext_pen->elpHatch == unset_hatch, "expected 0xb0b0b0b0, got %p\n", (void *)ext_pen->elpHatch);
275             ok(ext_pen->elpNumEntries == 0xb0b0b0b0, "expected 0xb0b0b0b0, got %x\n", ext_pen->elpNumEntries);
276             break;
277 
278         case PS_USERSTYLE:
279             ok(size == offsetof( EXTLOGPEN, elpStyleEntry[2] ),
280                "GetObject returned %d, error %d\n", size, GetLastError());
281             ok(ext_pen->elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen->elpHatch);
282             ok(ext_pen->elpNumEntries == 2, "expected 0, got %x\n", ext_pen->elpNumEntries);
283             ok(ext_style[0] == 0xabc, "expected 0xabc, got %x\n", ext_style[0]);
284             ok(ext_style[1] == 0xdef, "expected 0xdef, got %x\n", ext_style[1]);
285             break;
286 
287         default:
288             ok(size == offsetof( EXTLOGPEN, elpStyleEntry ),
289                "GetObject returned %d, error %d\n", size, GetLastError());
290             ok(ext_pen->elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen->elpHatch);
291             ok(ext_pen->elpNumEntries == 0, "expected 0, got %x\n", ext_pen->elpNumEntries);
292             break;
293         }
294 
295         ok(ext_pen->elpPenStyle == pen[i].style, "expected %x, got %x\n", pen[i].style, ext_pen->elpPenStyle);
296         ok(ext_pen->elpWidth == 1, "expected 1, got %x\n", ext_pen->elpWidth);
297         ok(ext_pen->elpColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, ext_pen->elpColor);
298         ok(ext_pen->elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %x\n", ext_pen->elpBrushStyle);
299 
300         DeleteObject(hpen);
301 
302 test_geometric_pens:
303         /********************** geometric pens **********************/
304         lb.lbStyle = BS_SOLID;
305         lb.lbColor = pen[i].color;
306         lb.lbHatch = HS_CROSS; /* just in case */
307         SetLastError(0xdeadbeef);
308         hpen = ExtCreatePen(PS_GEOMETRIC | pen[i].style, pen[i].width, &lb, 2, user_style);
309         if (pen[i].style != PS_USERSTYLE)
310         {
311             ok(hpen == 0, "ExtCreatePen should fail\n");
312             SetLastError(0xdeadbeef);
313             hpen = ExtCreatePen(PS_GEOMETRIC | pen[i].style, pen[i].width, &lb, 0, NULL);
314         }
315         if (pen[i].style == PS_ALTERNATE)
316         {
317             /* This style is applicable only for cosmetic pens */
318             ok(hpen == 0, "ExtCreatePen should fail\n");
319             continue;
320         }
321         if (pen[i].style > PS_ALTERNATE)
322         {
323             ok(hpen == 0, "ExtCreatePen should fail\n");
324             ok(GetLastError() == ERROR_INVALID_PARAMETER, "wrong last error value %d\n", GetLastError());
325             continue;
326         }
327         ok(hpen != 0, "ExtCreatePen error %d\n", GetLastError());
328 
329         obj_type = GetObjectType(hpen);
330         /* for some reason XP differentiates PS_NULL here */
331         if (pen[i].style == PS_NULL)
332             ok(obj_type == OBJ_PEN, "wrong object type %u\n", obj_type);
333         else
334             ok(obj_type == OBJ_EXTPEN, "wrong object type %u\n", obj_type);
335 
336         /* check what's the real size of the object */
337         size = GetObjectW(hpen, 0, NULL);
338         switch (pen[i].style)
339         {
340         case PS_NULL:
341             ok(size == sizeof(LOGPEN),
342                "GetObject returned %d, error %d\n", size, GetLastError());
343             break;
344 
345         case PS_USERSTYLE:
346             ok(size == offsetof( EXTLOGPEN, elpStyleEntry[2] ),
347                "GetObject returned %d, error %d\n", size, GetLastError());
348             break;
349 
350         default:
351             ok(size == offsetof( EXTLOGPEN, elpStyleEntry ),
352                "GetObject returned %d, error %d\n", size, GetLastError());
353             break;
354         }
355 
356         /* ask for truncated data */
357         memset(&lp, 0xb0, sizeof(lp));
358         SetLastError(0xdeadbeef);
359         size = GetObjectW(hpen, sizeof(lp.lopnStyle), &lp);
360         ok(!size, "GetObject should fail: size %d, error %d\n", size, GetLastError());
361 
362         memset(&lp, 0xb0, sizeof(lp));
363         SetLastError(0xdeadbeef);
364         size = GetObjectW(hpen, sizeof(lp), &lp);
365         /* for some reason XP differentiates PS_NULL here */
366         if (pen[i].style == PS_NULL)
367         {
368             ok(size == sizeof(LOGPEN), "GetObject returned %d, error %d\n", size, GetLastError());
369             ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
370             ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
371             ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
372             ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
373         }
374         else
375             /* XP doesn't set last error here */
376             ok(!size /*&& GetLastError() == ERROR_INVALID_PARAMETER*/,
377                "GetObject should fail: size %d, error %d\n", size, GetLastError());
378 
379         memset(elp_buffer, 0xb0, sizeof(elp_buffer));
380         SetLastError(0xdeadbeef);
381         /* buffer is too small for user styles */
382         size = GetObjectW(hpen, offsetof(EXTLOGPEN, elpStyleEntry[1]), elp_buffer);
383         switch (pen[i].style)
384         {
385         case PS_NULL:
386             ok(size == offsetof(EXTLOGPEN, elpStyleEntry[1]),
387                 "GetObject returned %d, error %d\n", size, GetLastError());
388             ok(ext_pen->elpHatch == 0, "expected 0, got %p\n", (void *)ext_pen->elpHatch);
389             ok(ext_pen->elpNumEntries == 0, "expected 0, got %x\n", ext_pen->elpNumEntries);
390 
391             /* for PS_NULL it also works this way */
392             SetLastError(0xdeadbeef);
393             size = GetObjectW(hpen, sizeof(elp_buffer), &lp);
394             ok(size == sizeof(LOGPEN),
395                 "GetObject returned %d, error %d\n", size, GetLastError());
396             ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
397             ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %d\n", pen[i].ret_width, lp.lopnWidth.x);
398             ok(lp.lopnWidth.y == 0, "expected 0, got %d\n", lp.lopnWidth.y);
399             ok(lp.lopnColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, lp.lopnColor);
400             break;
401 
402         case PS_USERSTYLE:
403             ok(!size /*&& GetLastError() == ERROR_INVALID_PARAMETER*/,
404                "GetObject should fail: size %d, error %d\n", size, GetLastError());
405             size = GetObjectW(hpen, sizeof(elp_buffer), elp_buffer);
406             ok(size == offsetof( EXTLOGPEN, elpStyleEntry[2] ),
407                "GetObject returned %d, error %d\n", size, GetLastError());
408             ok(ext_pen->elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen->elpHatch);
409             ok(ext_pen->elpNumEntries == 2, "expected 0, got %x\n", ext_pen->elpNumEntries);
410             ok(ext_style[0] == 0xabc, "expected 0xabc, got %x\n", ext_style[0]);
411             ok(ext_style[1] == 0xdef, "expected 0xdef, got %x\n", ext_style[1]);
412             break;
413 
414         default:
415             ok(size == offsetof( EXTLOGPEN, elpStyleEntry ),
416                "GetObject returned %d, error %d\n", size, GetLastError());
417             ok(ext_pen->elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen->elpHatch);
418             ok(ext_pen->elpNumEntries == 0, "expected 0, got %x\n", ext_pen->elpNumEntries);
419             break;
420         }
421 
422         /* for some reason XP differentiates PS_NULL here */
423         if (pen[i].style == PS_NULL)
424             ok(ext_pen->elpPenStyle == pen[i].ret_style, "expected %x, got %x\n", pen[i].ret_style, ext_pen->elpPenStyle);
425         else
426         {
427             ok(ext_pen->elpPenStyle == (PS_GEOMETRIC | pen[i].style), "expected %x, got %x\n", PS_GEOMETRIC | pen[i].style, ext_pen->elpPenStyle);
428         }
429 
430         if (pen[i].style == PS_NULL)
431             ok(ext_pen->elpWidth == 0, "expected 0, got %x\n", ext_pen->elpWidth);
432         else
433             ok(ext_pen->elpWidth == pen[i].ret_width, "expected %u, got %x\n", pen[i].ret_width, ext_pen->elpWidth);
434         ok(ext_pen->elpColor == pen[i].ret_color, "expected %08x, got %08x\n", pen[i].ret_color, ext_pen->elpColor);
435         ok(ext_pen->elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %x\n", ext_pen->elpBrushStyle);
436 
437         DeleteObject(hpen);
438     }
439 }
440 
441 static unsigned int atoi2(const char *s)
442 {
443     unsigned int ret = 0;
444     while(*s) ret = (ret << 1) | (*s++ == '1');
445     return ret;
446 }
447 
448 #define TEST_LINE(x1, x2, z) \
449     { int buf = 0; \
450       SetBitmapBits(bmp, sizeof(buf), &buf); \
451       MoveToEx(hdc, x1, 0, NULL); \
452       LineTo(hdc, x2, 0); \
453       GetBitmapBits(bmp, sizeof(buf), &buf); \
454       expect(atoi2(z), buf); }
455 
456 static void test_ps_alternate(void)
457 {
458     HDC hdc;
459     HBITMAP bmp;
460     HPEN pen;
461     LOGBRUSH lb;
462     INT iRet;
463     HGDIOBJ hRet;
464 
465     lb.lbStyle = BS_SOLID;
466     lb.lbColor = RGB(0xff,0xff,0xff);
467 
468     SetLastError(0xdeadbeef);
469     pen = ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, NULL);
470     if(pen == NULL && GetLastError() == 0xdeadbeef) {
471         skip("looks like 9x, skipping PS_ALTERNATE tests\n");
472         return;
473     }
474     ok(pen != NULL, "gle=%d\n", GetLastError());
475     hdc = CreateCompatibleDC(NULL);
476     ok(hdc != NULL, "gle=%d\n", GetLastError());
477     bmp = CreateBitmap(8, 1, 1, 1, NULL);
478     ok(bmp != NULL, "gle=%d\n", GetLastError());
479     hRet = SelectObject(hdc, bmp);
480     ok(hRet != NULL, "gle=%d\n", GetLastError());
481     hRet = SelectObject(hdc, pen);
482     ok(hRet != NULL, "gle=%d\n", GetLastError());
483     iRet = SetBkMode(hdc, TRANSPARENT);
484     ok(iRet, "gle=%d\n", GetLastError());
485 
486     TEST_LINE(0, 1, "10000000")
487     TEST_LINE(0, 2, "10000000")
488     TEST_LINE(0, 3, "10100000")
489     TEST_LINE(0, 4, "10100000")
490     TEST_LINE(1, 4, "01010000")
491     TEST_LINE(1, 5, "01010000")
492     TEST_LINE(4, 8, "00001010")
493 
494     DeleteObject(pen);
495     DeleteObject(bmp);
496     DeleteDC(hdc);
497 }
498 
499 static void test_ps_userstyle(void)
500 {
501     static DWORD style[17] = {0, 2, 0, 4, 5, 0, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 17};
502     static DWORD bad_style[5] = {0, 0, 0, 0, 0};
503     static DWORD bad_style2[5] = {4, 7, 8, 3, -1};
504 
505     LOGBRUSH lb;
506     HPEN pen;
507     INT size, i;
508     char buffer[offsetof(EXTLOGPEN, elpStyleEntry) + 16 * sizeof(DWORD)];
509     EXTLOGPEN *ext_pen = (EXTLOGPEN *)buffer;
510 
511     lb.lbColor = 0x00ff0000;
512     lb.lbStyle = BS_SOLID;
513     lb.lbHatch = 0;
514 
515     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 3, NULL);
516     ok(pen == 0, "ExtCreatePen should fail\n");
517     expect(ERROR_INVALID_PARAMETER, GetLastError());
518     DeleteObject(pen);
519     SetLastError(0xdeadbeef);
520 
521     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 0, style);
522     ok(pen == 0, "ExtCreatePen should fail\n");
523     expect2(0xdeadbeef, ERROR_INVALID_PARAMETER, GetLastError());
524     DeleteObject(pen);
525     SetLastError(0xdeadbeef);
526 
527     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 17, style);
528     ok(pen == 0, "ExtCreatePen should fail\n");
529     expect(ERROR_INVALID_PARAMETER, GetLastError());
530     DeleteObject(pen);
531     SetLastError(0xdeadbeef);
532 
533     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, -1, style);
534     ok(pen == 0, "ExtCreatePen should fail\n");
535     expect(0xdeadbeef, GetLastError());
536     DeleteObject(pen);
537     SetLastError(0xdeadbeef);
538 
539     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 5, bad_style);
540     ok(pen == 0, "ExtCreatePen should fail\n");
541     expect(ERROR_INVALID_PARAMETER, GetLastError());
542     DeleteObject(pen);
543     SetLastError(0xdeadbeef);
544 
545     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 5, bad_style2);
546     ok(pen == 0, "ExtCreatePen should fail\n");
547     expect(ERROR_INVALID_PARAMETER, GetLastError());
548     DeleteObject(pen);
549     SetLastError(0xdeadbeef);
550 
551     pen = ExtCreatePen(PS_GEOMETRIC | PS_USERSTYLE, 50, &lb, 16, style);
552     ok(pen != 0, "ExtCreatePen should not fail\n");
553 
554     size = GetObjectW(pen, sizeof(buffer), ext_pen);
555     ok(size == offsetof(EXTLOGPEN, elpStyleEntry[16]), "wrong size %d\n", size);
556 
557     for(i = 0; i < 16; i++)
558         expect(style[i], ext_pen->elpStyleEntry[i]);
559 
560     DeleteObject(pen);
561 }
562 
563 static void test_brush_pens(void)
564 {
565     char buffer[offsetof(EXTLOGPEN, elpStyleEntry) + 16 * sizeof(DWORD)];
566     EXTLOGPEN *elp = (EXTLOGPEN *)buffer;
567     LOGBRUSH lb;
568     HPEN pen = 0;
569     DWORD size;
570     HBITMAP bmp = CreateBitmap( 8, 8, 1, 1, NULL );
571     BITMAPINFO *info;
572     HGLOBAL hmem;
573 
574     hmem = GlobalAlloc( GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(*info) + 16 * 16 * 4 );
575     info = GlobalLock( hmem );
576     info->bmiHeader.biSize        = sizeof(info->bmiHeader);
577     info->bmiHeader.biWidth       = 16;
578     info->bmiHeader.biHeight      = 16;
579     info->bmiHeader.biPlanes      = 1;
580     info->bmiHeader.biBitCount    = 32;
581     info->bmiHeader.biCompression = BI_RGB;
582 
583     for (lb.lbStyle = BS_SOLID; lb.lbStyle <= BS_MONOPATTERN + 1; lb.lbStyle++)
584     {
585         SetLastError( 0xdeadbeef );
586         memset( buffer, 0xcc, sizeof(buffer) );
587         trace( "testing brush style %u\n", lb.lbStyle );
588 
589         switch (lb.lbStyle)
590         {
591         case BS_SOLID:
592         case BS_HATCHED:
593             lb.lbColor = RGB(12,34,56);
594             lb.lbHatch = HS_CROSS;
595             pen = ExtCreatePen( PS_DOT | PS_GEOMETRIC, 3, &lb, 0, NULL );
596             ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() );
597             size = GetObjectW( pen, sizeof(buffer), elp );
598             ok( size == offsetof( EXTLOGPEN, elpStyleEntry ), "wrong size %u\n", size );
599             ok( elp->elpPenStyle == (PS_DOT | PS_GEOMETRIC), "wrong pen style %x\n", elp->elpPenStyle );
600             ok( elp->elpBrushStyle == lb.lbStyle, "wrong brush style %x\n", elp->elpBrushStyle );
601             ok( elp->elpColor == RGB(12,34,56), "wrong color %x\n", elp->elpColor );
602             ok( elp->elpHatch == HS_CROSS, "wrong hatch %lx\n", elp->elpHatch );
603             ok( elp->elpNumEntries == 0, "wrong entries %x\n", elp->elpNumEntries );
604             break;
605 
606         case BS_NULL:
607             pen = ExtCreatePen( PS_SOLID | PS_GEOMETRIC, 3, &lb, 0, NULL );
608             ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() );
609             size = GetObjectW( pen, sizeof(buffer), elp );
610             ok( size == sizeof(LOGPEN), "wrong size %u\n", size );
611             ok( ((LOGPEN *)elp)->lopnStyle == PS_NULL,
612                 "wrong pen style %x\n", ((LOGPEN *)elp)->lopnStyle );
613             ok( ((LOGPEN *)elp)->lopnColor == 0,
614                 "wrong color %x\n", ((LOGPEN *)elp)->lopnColor );
615             break;
616 
617         case BS_PATTERN:
618             lb.lbColor = RGB(12,34,56);
619             lb.lbHatch = (ULONG_PTR)bmp;
620             pen = ExtCreatePen( PS_DOT | PS_GEOMETRIC, 3, &lb, 0, NULL );
621             ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() );
622             size = GetObjectW( pen, sizeof(buffer), elp );
623             ok( size == offsetof( EXTLOGPEN, elpStyleEntry ), "wrong size %u\n", size );
624             ok( elp->elpPenStyle == (PS_DOT | PS_GEOMETRIC), "wrong pen style %x\n", elp->elpPenStyle );
625             ok( elp->elpBrushStyle == BS_PATTERN, "wrong brush style %x\n", elp->elpBrushStyle );
626             ok( elp->elpColor == 0, "wrong color %x\n", elp->elpColor );
627             ok( elp->elpHatch == (ULONG_PTR)bmp, "wrong hatch %lx/%p\n", elp->elpHatch, bmp );
628             ok( elp->elpNumEntries == 0, "wrong entries %x\n", elp->elpNumEntries );
629             break;
630 
631         case BS_DIBPATTERN:
632         case BS_DIBPATTERNPT:
633             lb.lbColor = DIB_PAL_COLORS;
634             lb.lbHatch = lb.lbStyle == BS_DIBPATTERN ? (ULONG_PTR)hmem : (ULONG_PTR)info;
635             pen = ExtCreatePen( PS_DOT | PS_GEOMETRIC, 3, &lb, 0, NULL );
636             ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() );
637             size = GetObjectW( pen, sizeof(buffer), elp );
638             ok( size == offsetof( EXTLOGPEN, elpStyleEntry ), "wrong size %u\n", size );
639             ok( elp->elpPenStyle == (PS_DOT | PS_GEOMETRIC), "wrong pen style %x\n", elp->elpPenStyle );
640             ok( elp->elpBrushStyle == BS_DIBPATTERNPT, "wrong brush style %x\n", elp->elpBrushStyle );
641             ok( elp->elpColor == 0, "wrong color %x\n", elp->elpColor );
642             ok( elp->elpHatch == lb.lbHatch || broken(elp->elpHatch != lb.lbHatch), /* <= w2k */
643                 "wrong hatch %lx/%lx\n", elp->elpHatch, lb.lbHatch );
644             ok( elp->elpNumEntries == 0, "wrong entries %x\n", elp->elpNumEntries );
645             break;
646 
647         default:
648             pen = ExtCreatePen( PS_DOT | PS_GEOMETRIC, 3, &lb, 0, NULL );
649             ok( !pen, "ExtCreatePen succeeded\n" );
650             ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
651             break;
652         }
653 
654         if (pen) DeleteObject( pen );
655         else continue;
656 
657         /* cosmetic pens require BS_SOLID */
658         SetLastError( 0xdeadbeef );
659         pen = ExtCreatePen( PS_DOT, 1, &lb, 0, NULL );
660         if (lb.lbStyle == BS_SOLID)
661         {
662             ok( pen != 0, "ExtCreatePen failed err %u\n", GetLastError() );
663             size = GetObjectW( pen, sizeof(buffer), elp );
664             ok( size == offsetof( EXTLOGPEN, elpStyleEntry ), "wrong size %u\n", size );
665             ok( elp->elpPenStyle == PS_DOT, "wrong pen style %x\n", elp->elpPenStyle );
666             ok( elp->elpBrushStyle == BS_SOLID, "wrong brush style %x\n", elp->elpBrushStyle );
667             ok( elp->elpColor == RGB(12,34,56), "wrong color %x\n", elp->elpColor );
668             ok( elp->elpHatch == HS_CROSS, "wrong hatch %lx\n", elp->elpHatch );
669             DeleteObject( pen );
670         }
671         else
672         {
673             ok( !pen, "ExtCreatePen succeeded\n" );
674             ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
675         }
676     }
677 
678     GlobalUnlock( hmem );
679     GlobalFree( hmem );
680     DeleteObject( bmp );
681 }
682 
683 START_TEST(pen)
684 {
685     test_logpen();
686     test_brush_pens();
687     test_ps_alternate();
688     test_ps_userstyle();
689 }
690