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