gdi: Add support for creating extended pens.
diff --git a/dlls/gdi/enhmfdrv/objects.c b/dlls/gdi/enhmfdrv/objects.c
index 8c51f63..9d8b14d 100644
--- a/dlls/gdi/enhmfdrv/objects.c
+++ b/dlls/gdi/enhmfdrv/objects.c
@@ -398,7 +398,20 @@
     EMRCREATEPEN emr;
     DWORD index = 0;
 
-    if (!GetObjectA( hPen, sizeof(emr.lopn), &emr.lopn )) return 0;
+    if (!GetObjectW( hPen, sizeof(emr.lopn), &emr.lopn ))
+    {
+        /* must be an extended pen */
+        EXTLOGPEN elp;
+        if (!GetObjectW( hPen, sizeof(elp), &elp ))
+        {
+            FIXME("extended pen %p not supported\n", hPen);
+            return 0;
+        }
+        emr.lopn.lopnStyle = elp.elpPenStyle;
+        emr.lopn.lopnWidth.x = elp.elpWidth;
+        emr.lopn.lopnWidth.y = 0;
+        emr.lopn.lopnColor = elp.elpColor;
+    }
 
     emr.emr.iType = EMR_CREATEPEN;
     emr.emr.nSize = sizeof(emr);
diff --git a/dlls/gdi/gdiobj.c b/dlls/gdi/gdiobj.c
index 03828f7..a4c9a07 100644
--- a/dlls/gdi/gdiobj.c
+++ b/dlls/gdi/gdiobj.c
@@ -1033,6 +1033,9 @@
       case PEN_MAGIC:
 	  result = OBJ_PEN;
 	  break;
+      case EXT_PEN_MAGIC:
+	  result = OBJ_EXTPEN;
+	  break;
       case BRUSH_MAGIC:
 	  result = OBJ_BRUSH;
 	  break;
@@ -1288,7 +1291,7 @@
     GDIOBJHDR *object = GDI_GetObjPtr( handle, MAGIC_DONTCARE );
     if (object)
     {
-        magic = GDIMAGIC(object->wMagic) - PEN_MAGIC + 1;
+        magic = GDIMAGIC(object->wMagic) - FIRST_MAGIC + 1;
         GDI_ReleaseObj( handle );
     }
     return magic;
diff --git a/dlls/gdi/mfdrv/objects.c b/dlls/gdi/mfdrv/objects.c
index 1cda8fe..e0859ac 100644
--- a/dlls/gdi/mfdrv/objects.c
+++ b/dlls/gdi/mfdrv/objects.c
@@ -404,7 +404,20 @@
     if( index < 0 )
     {
         if (!GetObject16( HPEN_16(hpen), sizeof(logpen), &logpen ))
-            return 0;
+        {
+            /* must be an extended pen */
+            EXTLOGPEN elp;
+            if (!GetObjectW( hpen, sizeof(elp), &elp ))
+            {
+                FIXME("extended pen %p not supported\n", hpen);
+                return 0;
+            }
+            logpen.lopnStyle = elp.elpPenStyle;
+            logpen.lopnWidth.x = elp.elpWidth;
+            logpen.lopnWidth.y = 0;
+            logpen.lopnColor = elp.elpColor;
+        }
+
         index = MFDRV_CreatePenIndirect( dev, hpen, &logpen );
         if( index < 0 )
             return 0;
diff --git a/dlls/gdi/pen.c b/dlls/gdi/pen.c
index f165c82..0e4d686 100644
--- a/dlls/gdi/pen.c
+++ b/dlls/gdi/pen.c
@@ -23,6 +23,7 @@
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
+#include <assert.h>
 
 #include "windef.h"
 #include "winbase.h"
@@ -37,8 +38,8 @@
   /* GDI logical pen object */
 typedef struct
 {
-    GDIOBJHDR   header;
-    LOGPEN    logpen;
+    GDIOBJHDR header;
+    EXTLOGPEN logpen;
 } PENOBJ;
 
 
@@ -86,20 +87,24 @@
     if (!(penPtr = GDI_AllocObject( sizeof(PENOBJ), PEN_MAGIC, (HGDIOBJ *)&hpen,
 				    &pen_funcs ))) return 0;
     if (pen->lopnStyle == PS_USERSTYLE || pen->lopnStyle == PS_ALTERNATE)
-        penPtr->logpen.lopnStyle = PS_SOLID;
+        penPtr->logpen.elpPenStyle = PS_SOLID;
     else
-        penPtr->logpen.lopnStyle = pen->lopnStyle;
-    penPtr->logpen.lopnWidth.y = 0;
+        penPtr->logpen.elpPenStyle = pen->lopnStyle;
     if (pen->lopnStyle == PS_NULL)
     {
-        penPtr->logpen.lopnWidth.x = 1;
-        penPtr->logpen.lopnColor = RGB(0, 0, 0);
+        penPtr->logpen.elpWidth = 1;
+        penPtr->logpen.elpColor = RGB(0, 0, 0);
     }
     else
     {
-        penPtr->logpen.lopnWidth.x = abs(pen->lopnWidth.x);
-        penPtr->logpen.lopnColor = pen->lopnColor;
+        penPtr->logpen.elpWidth = abs(pen->lopnWidth.x);
+        penPtr->logpen.elpColor = pen->lopnColor;
     }
+    penPtr->logpen.elpBrushStyle = BS_SOLID;
+    penPtr->logpen.elpHatch = 0;
+    penPtr->logpen.elpNumEntries = 0;
+    penPtr->logpen.elpStyleEntry[0] = 0;
+
     GDI_ReleaseObj( hpen );
     return hpen;
 }
@@ -118,23 +123,63 @@
     HPEN hpen;
 
     if ((style & PS_STYLE_MASK) == PS_USERSTYLE)
-	FIXME("PS_USERSTYLE not handled\n");
+    {
+        if (!style_count || !style_bits)
+        {
+            SetLastError(ERROR_INVALID_PARAMETER);
+            return 0;
+        }
+        /* FIXME: PS_USERSTYLE workaround */
+        FIXME("PS_USERSTYLE not handled\n");
+        style = (style & ~PS_STYLE_MASK) | PS_SOLID;
+    }
+    else
+    {
+        if (style_count || style_bits)
+        {
+            SetLastError(ERROR_INVALID_PARAMETER);
+            return 0;
+        }
+    }
+
+    if ((style & PS_STYLE_MASK) == PS_NULL)
+        return CreatePen( PS_NULL, 0, brush->lbColor );
+
     if ((style & PS_TYPE_MASK) == PS_GEOMETRIC)
+    {
+        /* PS_ALTERNATE is applicable only for cosmetic pens */
+        if ((style & PS_STYLE_MASK) == PS_ALTERNATE)
+        {
+            SetLastError(ERROR_INVALID_PARAMETER);
+            return 0;
+        }
+
 	if (brush->lbHatch && ((brush->lbStyle == BS_SOLID) || (brush->lbStyle == BS_HOLLOW)))
 	    FIXME("Hatches not implemented\n");	
+    }
+    else
+    {
+        /* PS_INSIDEFRAME is applicable only for gemetric pens */
+        if ((style & PS_STYLE_MASK) == PS_INSIDEFRAME || width != 1)
+        {
+            SetLastError(ERROR_INVALID_PARAMETER);
+            return 0;
+        }
+    }
 
-    if (!(penPtr = GDI_AllocObject( sizeof(PENOBJ), PEN_MAGIC, (HGDIOBJ *)&hpen,
+    if (!(penPtr = GDI_AllocObject( sizeof(PENOBJ) +
+                                    style_count * sizeof(DWORD) - sizeof(penPtr->logpen.elpStyleEntry),
+                                    EXT_PEN_MAGIC, (HGDIOBJ *)&hpen,
 				    &pen_funcs ))) return 0;
-    penPtr->logpen.lopnStyle = style & ~PS_TYPE_MASK;
 
-    /* PS_USERSTYLE workaround */
-    if((penPtr->logpen.lopnStyle & PS_STYLE_MASK) == PS_USERSTYLE)
-       penPtr->logpen.lopnStyle =
-         (penPtr->logpen.lopnStyle & ~PS_STYLE_MASK) | PS_SOLID;
-
-    penPtr->logpen.lopnWidth.x = (style & PS_GEOMETRIC) ? width : 1;
-    penPtr->logpen.lopnWidth.y = 0;
-    penPtr->logpen.lopnColor = brush->lbColor;
+    penPtr->logpen.elpPenStyle = style;
+    penPtr->logpen.elpWidth = abs(width);
+    penPtr->logpen.elpBrushStyle = brush->lbStyle;
+    penPtr->logpen.elpColor = brush->lbColor;
+    penPtr->logpen.elpHatch = brush->lbHatch;
+    penPtr->logpen.elpNumEntries = style_count;
+    memcpy(penPtr->logpen.elpStyleEntry, style_bits, style_count * sizeof(DWORD));
+    
     GDI_ReleaseObj( hpen );
 
     return hpen;
@@ -165,15 +210,19 @@
 static INT PEN_GetObject16( HGDIOBJ handle, void *obj, INT count, LPVOID buffer )
 {
     PENOBJ *pen = obj;
-    LOGPEN16 logpen;
+    LOGPEN16 *logpen;
 
-    logpen.lopnStyle = pen->logpen.lopnStyle;
-    logpen.lopnColor = pen->logpen.lopnColor;
-    logpen.lopnWidth.x = pen->logpen.lopnWidth.x;
-    logpen.lopnWidth.y = pen->logpen.lopnWidth.y;
-    if (count > sizeof(logpen)) count = sizeof(logpen);
-    memcpy( buffer, &logpen, count );
-    return count;
+    if (!buffer) return sizeof(LOGPEN16);
+
+    if (count < sizeof(LOGPEN16)) return 0;
+
+    logpen = buffer;
+    logpen->lopnStyle = pen->logpen.elpPenStyle;
+    logpen->lopnColor = pen->logpen.elpColor;
+    logpen->lopnWidth.x = pen->logpen.elpWidth;
+    logpen->lopnWidth.y = 0;
+
+    return sizeof(LOGPEN16);
 }
 
 
@@ -184,21 +233,47 @@
 {
     PENOBJ *pen = obj;
 
-    if( !buffer )
-        return sizeof(pen->logpen);
-
-    switch (count)
+    switch (GDIMAGIC(pen->header.wMagic))
     {
-    case sizeof(EXTLOGPEN):
-        FIXME("extended pens not supported\n");
-        return 0;
+    case PEN_MAGIC:
+    {
+        LOGPEN *lp;
 
-    case sizeof(LOGPEN):
-        memcpy( buffer, &pen->logpen, sizeof(LOGPEN) );
+        if (!buffer) return sizeof(LOGPEN);
+
+        if (count < sizeof(LOGPEN)) return 0;
+
+        if ((pen->logpen.elpPenStyle & PS_STYLE_MASK) == PS_NULL &&
+            count == sizeof(EXTLOGPEN))
+        {
+            EXTLOGPEN *elp = buffer;
+            memcpy(elp, &pen->logpen, sizeof(EXTLOGPEN));
+            elp->elpWidth = 0;
+            return sizeof(EXTLOGPEN);
+        }
+
+        lp = buffer;
+        lp->lopnStyle = pen->logpen.elpPenStyle;
+        lp->lopnColor = pen->logpen.elpColor;
+        lp->lopnWidth.x = pen->logpen.elpWidth;
+        lp->lopnWidth.y = 0;
         return sizeof(LOGPEN);
+    }
+
+    case EXT_PEN_MAGIC:
+    {
+        INT size = sizeof(EXTLOGPEN) + pen->logpen.elpNumEntries * sizeof(DWORD) - sizeof(pen->logpen.elpStyleEntry);
+
+        if (!buffer) return size;
+
+        if (count < size) return 0;
+        memcpy(buffer, &pen->logpen, size);
+        return size;
+    }
 
     default:
         break;
     }
+    assert(0);
     return 0;
 }
diff --git a/dlls/gdi/tests/gdiobj.c b/dlls/gdi/tests/gdiobj.c
index 7c5f505..463bbf4 100644
--- a/dlls/gdi/tests/gdiobj.c
+++ b/dlls/gdi/tests/gdiobj.c
@@ -523,7 +523,7 @@
     LOGPEN lp;
     EXTLOGPEN elp;
     LOGBRUSH lb;
-    DWORD user_style[2] = { 1, 2 };
+    DWORD obj_type, user_style[2] = { 0xabc, 0xdef };
     struct
     {
         EXTLOGPEN elp;
@@ -535,10 +535,38 @@
         trace("testing style %u\n", pen[i].style);
 
         /********************** cosmetic pens **********************/
+        /* CreatePenIndirect behaviour */
+        lp.lopnStyle = pen[i].style,
+        lp.lopnWidth.x = pen[i].width;
+        lp.lopnWidth.y = 11; /* just in case */
+        lp.lopnColor = pen[i].color;
+        SetLastError(0xdeadbeef);
+        hpen = CreatePenIndirect(&lp);
+        ok(hpen != 0, "CreatePen error %ld\n", GetLastError());
+
+        obj_type = GetObjectType(hpen);
+        ok(obj_type == OBJ_PEN, "wrong object type %lu\n", obj_type);
+
+        memset(&lp, 0xb0, sizeof(lp));
+        SetLastError(0xdeadbeef);
+        size = GetObject(hpen, sizeof(lp), &lp);
+        ok(size == sizeof(lp), "GetObject returned %d, error %ld\n", size, GetLastError());
+
+        ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
+        ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %ld\n", pen[i].ret_width, lp.lopnWidth.x);
+        ok(lp.lopnWidth.y == 0, "expected 0, got %ld\n", lp.lopnWidth.y);
+        ok(lp.lopnColor == pen[i].ret_color, "expected %08lx, got %08lx\n", pen[i].ret_color, lp.lopnColor);
+
+        DeleteObject(hpen);
+
+        /* CreatePen behaviour */
         SetLastError(0xdeadbeef);
         hpen = CreatePen(pen[i].style, pen[i].width, pen[i].color);
         ok(hpen != 0, "CreatePen error %ld\n", GetLastError());
 
+        obj_type = GetObjectType(hpen);
+        ok(obj_type == OBJ_PEN, "wrong object type %lu\n", obj_type);
+
         /* check what's the real size of the object */
         size = GetObject(hpen, 0, NULL);
         ok(size == sizeof(lp), "GetObject returned %d, error %ld\n", size, GetLastError());
@@ -549,6 +577,18 @@
         size = GetObject(hpen, sizeof(lp.lopnStyle), &lp);
         ok(!size, "GetObject should fail: size %d, error %ld\n", size, GetLastError());
 
+        /* see how larger buffer sizes are handled */
+        memset(&lp, 0xb0, sizeof(lp));
+        SetLastError(0xdeadbeef);
+        size = GetObject(hpen, sizeof(lp) * 2, &lp);
+        ok(size == sizeof(lp), "GetObject returned %d, error %ld\n", size, GetLastError());
+
+        /* see how larger buffer sizes are handled */
+        memset(&elp, 0xb0, sizeof(elp));
+        SetLastError(0xdeadbeef);
+        size = GetObject(hpen, sizeof(elp) * 2, &elp);
+        ok(size == sizeof(lp), "GetObject returned %d, error %ld\n", size, GetLastError());
+
         memset(&lp, 0xb0, sizeof(lp));
         SetLastError(0xdeadbeef);
         size = GetObject(hpen, sizeof(lp), &lp);
@@ -562,39 +602,159 @@
         memset(&elp, 0xb0, sizeof(elp));
         SetLastError(0xdeadbeef);
         size = GetObject(hpen, sizeof(elp), &elp);
-/* todo_wine: Wine doesn't support extended pens at all, skip all other tests */
-if (!size) continue;
 
         /* for some reason XP differentiates PS_NULL here */
         if (pen[i].style == PS_NULL)
-            ok(size == sizeof(EXTLOGPEN), "GetObject returned %d, error %ld\n", size, GetLastError());
-        else
-            ok(size == sizeof(LOGPEN), "GetObject returned %d, error %ld\n", size, GetLastError());
-
-        ok(elp.elpPenStyle == pen[i].ret_style, "expected %u, got %lu\n", pen[i].ret_style, elp.elpPenStyle);
-        if (pen[i].style == PS_NULL)
-            ok(elp.elpWidth == 0, "expected %u, got %lu\n", pen[i].ret_width, elp.elpWidth);
-        else
-            ok(elp.elpWidth == pen[i].ret_width, "expected %u, got %lu\n", pen[i].ret_width, elp.elpWidth);
-        ok(elp.elpColor == pen[i].ret_color, "expected %08lx, got %08lx\n", pen[i].ret_color, elp.elpColor);
-        ok(elp.elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %u\n", elp.elpBrushStyle);
-
-        /* for some reason XP differenciates PS_NULL here */
-        if (pen[i].style == PS_NULL)
         {
+            ok(size == sizeof(EXTLOGPEN), "GetObject returned %d, error %ld\n", size, GetLastError());
+            ok(elp.elpPenStyle == pen[i].ret_style, "expected %u, got %lu\n", pen[i].ret_style, elp.elpPenStyle);
+            ok(elp.elpWidth == 0, "expected 0, got %lu\n", elp.elpWidth);
+            ok(elp.elpColor == pen[i].ret_color, "expected %08lx, got %08lx\n", pen[i].ret_color, elp.elpColor);
+            ok(elp.elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %u\n", elp.elpBrushStyle);
             ok(elp.elpHatch == 0, "expected 0, got %p\n", (void *)elp.elpHatch);
             ok(elp.elpNumEntries == 0, "expected 0, got %lx\n", elp.elpNumEntries);
         }
         else
         {
-            ok(elp.elpHatch == 0xb0b0b0b0, "expected 0xb0b0b0b0, got %p\n", (void *)elp.elpHatch);
-            ok(elp.elpNumEntries == 0xb0b0b0b0, "expected 0xb0b0b0b0, got %lx\n", elp.elpNumEntries);
+            ok(size == sizeof(LOGPEN), "GetObject returned %d, error %ld\n", size, GetLastError());
+            memcpy(&lp, &elp, sizeof(lp));
+            ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
+            ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %ld\n", pen[i].ret_width, lp.lopnWidth.x);
+            ok(lp.lopnWidth.y == 0, "expected 0, got %ld\n", lp.lopnWidth.y);
+            ok(lp.lopnColor == pen[i].ret_color, "expected %08lx, got %08lx\n", pen[i].ret_color, lp.lopnColor);
         }
-#if 0   /* XP returns garbage here */
-        ok(elp.elpStyleEntry[0] == 0xb0b0b0b0, "expected 0xb0b0b0b0, got %lx\n", elp.elpStyleEntry[0]);
-#endif
+
         DeleteObject(hpen);
 
+        /********** cosmetic pens created by ExtCreatePen ***********/
+        lb.lbStyle = BS_SOLID;
+        lb.lbColor = pen[i].color;
+        lb.lbHatch = HS_CROSS; /* just in case */
+        SetLastError(0xdeadbeef);
+        hpen = ExtCreatePen(pen[i].style, pen[i].width, &lb, 2, user_style);
+        if (pen[i].style != PS_USERSTYLE)
+        {
+            ok(hpen == 0, "ExtCreatePen should fail\n");
+            ok(GetLastError() == ERROR_INVALID_PARAMETER,
+               "wrong last error value %ld\n", GetLastError());
+            SetLastError(0xdeadbeef);
+            hpen = ExtCreatePen(pen[i].style, pen[i].width, &lb, 0, NULL);
+            if (pen[i].style != PS_NULL)
+            {
+                ok(hpen == 0, "ExtCreatePen with width != 1 should fail\n");
+                ok(GetLastError() == ERROR_INVALID_PARAMETER,
+                   "wrong last error value %ld\n", GetLastError());
+
+                SetLastError(0xdeadbeef);
+                hpen = ExtCreatePen(pen[i].style, 1, &lb, 0, NULL);
+            }
+        }
+        else
+        {
+            ok(hpen == 0, "ExtCreatePen with width != 1 should fail\n");
+            ok(GetLastError() == ERROR_INVALID_PARAMETER,
+               "wrong last error value %ld\n", GetLastError());
+            SetLastError(0xdeadbeef);
+            hpen = ExtCreatePen(pen[i].style, 1, &lb, 2, user_style);
+        }
+        if (pen[i].style == PS_INSIDEFRAME)
+        {
+            /* This style is applicable only for gemetric pens */
+            ok(hpen == 0, "ExtCreatePen should fail\n");
+            goto test_geometric_pens;
+        }
+        ok(hpen != 0, "ExtCreatePen error %ld\n", GetLastError());
+
+        obj_type = GetObjectType(hpen);
+        /* for some reason XP differentiates PS_NULL here */
+        if (pen[i].style == PS_NULL)
+            ok(obj_type == OBJ_PEN, "wrong object type %lu\n", obj_type);
+        else
+            ok(obj_type == OBJ_EXTPEN, "wrong object type %lu\n", obj_type);
+
+        /* check what's the real size of the object */
+        SetLastError(0xdeadbeef);
+        size = GetObject(hpen, 0, NULL);
+        switch (pen[i].style)
+        {
+        case PS_NULL:
+            ok(size == sizeof(LOGPEN),
+               "GetObject returned %d, error %ld\n", size, GetLastError());
+            break;
+
+        case PS_USERSTYLE:
+            ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry) + sizeof(user_style),
+               "GetObject returned %d, error %ld\n", size, GetLastError());
+            break;
+
+        default:
+            ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry),
+               "GetObject returned %d, error %ld\n", size, GetLastError());
+            break;
+        }
+
+        /* ask for truncated data */
+        memset(&elp, 0xb0, sizeof(elp));
+        SetLastError(0xdeadbeef);
+        size = GetObject(hpen, sizeof(elp.elpPenStyle), &elp);
+        ok(!size, "GetObject should fail: size %d, error %ld\n", size, GetLastError());
+
+        /* see how larger buffer sizes are handled */
+        memset(&ext_pen, 0xb0, sizeof(ext_pen));
+        SetLastError(0xdeadbeef);
+        size = GetObject(hpen, sizeof(ext_pen), &ext_pen.elp);
+        switch (pen[i].style)
+        {
+        case PS_NULL:
+            ok(size == sizeof(LOGPEN),
+               "GetObject returned %d, error %ld\n", size, GetLastError());
+            memcpy(&lp, &ext_pen.elp, sizeof(lp));
+            ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
+            ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %ld\n", pen[i].ret_width, lp.lopnWidth.x);
+            ok(lp.lopnWidth.y == 0, "expected 0, got %ld\n", lp.lopnWidth.y);
+            ok(lp.lopnColor == pen[i].ret_color, "expected %08lx, got %08lx\n", pen[i].ret_color, lp.lopnColor);
+
+            /* for PS_NULL it also works this way */
+            memset(&elp, 0xb0, sizeof(elp));
+            SetLastError(0xdeadbeef);
+            size = GetObject(hpen, sizeof(elp), &elp);
+            ok(size == sizeof(EXTLOGPEN),
+                "GetObject returned %d, error %ld\n", size, GetLastError());
+            ok(ext_pen.elp.elpHatch == 0xb0b0b0b0, "expected 0xb0b0b0b0, got %p\n", (void *)ext_pen.elp.elpHatch);
+            ok(ext_pen.elp.elpNumEntries == 0xb0b0b0b0, "expected 0xb0b0b0b0, got %lx\n", ext_pen.elp.elpNumEntries);
+            break;
+
+        case PS_USERSTYLE:
+            ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry) + sizeof(user_style),
+               "GetObject returned %d, error %ld\n", size, GetLastError());
+            ok(ext_pen.elp.elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen.elp.elpHatch);
+            ok(ext_pen.elp.elpNumEntries == 2, "expected 0, got %lx\n", ext_pen.elp.elpNumEntries);
+            ok(ext_pen.elp.elpStyleEntry[0] == 0xabc, "expected 0xabc, got %lx\n", ext_pen.elp.elpStyleEntry[0]);
+            ok(ext_pen.elp.elpStyleEntry[1] == 0xdef, "expected 0xabc, got %lx\n", ext_pen.elp.elpStyleEntry[1]);
+            break;
+
+        default:
+            ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry),
+               "GetObject returned %d, error %ld\n", size, GetLastError());
+            ok(ext_pen.elp.elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen.elp.elpHatch);
+            ok(ext_pen.elp.elpNumEntries == 0, "expected 0, got %lx\n", ext_pen.elp.elpNumEntries);
+            break;
+        }
+
+if (pen[i].style == PS_USERSTYLE)
+{
+    todo_wine
+        ok(ext_pen.elp.elpPenStyle == pen[i].style, "expected %x, got %lx\n", pen[i].style, ext_pen.elp.elpPenStyle);
+}
+else
+        ok(ext_pen.elp.elpPenStyle == pen[i].style, "expected %x, got %lx\n", pen[i].style, ext_pen.elp.elpPenStyle);
+        ok(ext_pen.elp.elpWidth == 1, "expected 1, got %lx\n", ext_pen.elp.elpWidth);
+        ok(ext_pen.elp.elpColor == pen[i].ret_color, "expected %08lx, got %08lx\n", pen[i].ret_color, ext_pen.elp.elpColor);
+        ok(ext_pen.elp.elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %x\n", ext_pen.elp.elpBrushStyle);
+
+        DeleteObject(hpen);
+
+test_geometric_pens:
         /********************** geometric pens **********************/
         lb.lbStyle = BS_SOLID;
         lb.lbColor = pen[i].color;
@@ -604,10 +764,23 @@
         if (pen[i].style != PS_USERSTYLE)
         {
             ok(hpen == 0, "ExtCreatePen should fail\n");
+            SetLastError(0xdeadbeef);
             hpen = ExtCreatePen(PS_GEOMETRIC | pen[i].style, pen[i].width, &lb, 0, NULL);
         }
+        if (pen[i].style == PS_ALTERNATE)
+        {
+            /* This style is applicable only for cosmetic pens */
+            ok(hpen == 0, "ExtCreatePen should fail\n");
+            continue;
+        }
+        ok(hpen != 0, "ExtCreatePen error %ld\n", GetLastError());
+
+        obj_type = GetObjectType(hpen);
+        /* for some reason XP differentiates PS_NULL here */
+        if (pen[i].style == PS_NULL)
+            ok(obj_type == OBJ_PEN, "wrong object type %lu\n", obj_type);
         else
-            ok(hpen != 0, "ExtCreatePen error %ld\n", GetLastError());
+            ok(obj_type == OBJ_EXTPEN, "wrong object type %lu\n", obj_type);
 
         /* check what's the real size of the object */
         size = GetObject(hpen, 0, NULL);
@@ -618,11 +791,6 @@
                "GetObject returned %d, error %ld\n", size, GetLastError());
             break;
 
-        case PS_ALTERNATE:
-            ok(size == 0 /*&& GetLastError() == ERROR_INVALID_PARAMETER*/,
-               "GetObject should fail: size %d, error %ld\n", size, GetLastError());
-            break;
-
         case PS_USERSTYLE:
             ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry) + sizeof(user_style),
                "GetObject returned %d, error %ld\n", size, GetLastError());
@@ -654,12 +822,13 @@
         }
         else
             /* XP doesn't set last error here */
-            ok(size == 0 /*&& GetLastError() == ERROR_INVALID_PARAMETER*/,
+            ok(!size /*&& GetLastError() == ERROR_INVALID_PARAMETER*/,
                "GetObject should fail: size %d, error %ld\n", size, GetLastError());
 
-        memset(&elp, 0xb0, sizeof(elp));
+        memset(&ext_pen, 0xb0, sizeof(ext_pen));
         SetLastError(0xdeadbeef);
-        size = GetObject(hpen, sizeof(elp), &ext_pen);
+        /* buffer is too small for user styles */
+        size = GetObject(hpen, sizeof(elp), &ext_pen.elp);
         switch (pen[i].style)
         {
         case PS_NULL:
@@ -667,23 +836,28 @@
                 "GetObject returned %d, error %ld\n", size, GetLastError());
             ok(ext_pen.elp.elpHatch == 0, "expected 0, got %p\n", (void *)ext_pen.elp.elpHatch);
             ok(ext_pen.elp.elpNumEntries == 0, "expected 0, got %lx\n", ext_pen.elp.elpNumEntries);
-            break;
 
-        case PS_ALTERNATE:
-            ok(size == 0 /*&& GetLastError() == ERROR_INVALID_PARAMETER*/,
-               "GetObject should fail: size %d, error %ld\n", size, GetLastError());
-            size = GetObject(hpen, sizeof(ext_pen), &ext_pen);
-            /* for PS_ALTERNATE it still fails under XP SP2 */
-            ok(size == 0,
-               "GetObject should fail: size %d, error %ld\n", size, GetLastError());
+            /* for PS_NULL it also works this way */
+            SetLastError(0xdeadbeef);
+            size = GetObject(hpen, sizeof(ext_pen), &lp);
+            ok(size == sizeof(LOGPEN),
+                "GetObject returned %d, error %ld\n", size, GetLastError());
+            ok(lp.lopnStyle == pen[i].ret_style, "expected %u, got %u\n", pen[i].ret_style, lp.lopnStyle);
+            ok(lp.lopnWidth.x == pen[i].ret_width, "expected %u, got %ld\n", pen[i].ret_width, lp.lopnWidth.x);
+            ok(lp.lopnWidth.y == 0, "expected 0, got %ld\n", lp.lopnWidth.y);
+            ok(lp.lopnColor == pen[i].ret_color, "expected %08lx, got %08lx\n", pen[i].ret_color, lp.lopnColor);
             break;
 
         case PS_USERSTYLE:
-            ok(size == 0 /*&& GetLastError() == ERROR_INVALID_PARAMETER*/,
+            ok(!size /*&& GetLastError() == ERROR_INVALID_PARAMETER*/,
                "GetObject should fail: size %d, error %ld\n", size, GetLastError());
-            size = GetObject(hpen, sizeof(ext_pen), &ext_pen);
+            size = GetObject(hpen, sizeof(ext_pen), &ext_pen.elp);
             ok(size == sizeof(EXTLOGPEN) - sizeof(elp.elpStyleEntry) + sizeof(user_style),
                "GetObject returned %d, error %ld\n", size, GetLastError());
+            ok(ext_pen.elp.elpHatch == HS_CROSS, "expected HS_CROSS, got %p\n", (void *)ext_pen.elp.elpHatch);
+            ok(ext_pen.elp.elpNumEntries == 2, "expected 0, got %lx\n", ext_pen.elp.elpNumEntries);
+            ok(ext_pen.elp.elpStyleEntry[0] == 0xabc, "expected 0xabc, got %lx\n", ext_pen.elp.elpStyleEntry[0]);
+            ok(ext_pen.elp.elpStyleEntry[1] == 0xdef, "expected 0xabc, got %lx\n", ext_pen.elp.elpStyleEntry[1]);
             break;
 
         default:
@@ -694,24 +868,27 @@
             break;
         }
 
-        if (size != 0)
+        /* for some reason XP differenciates PS_NULL here */
+        if (pen[i].style == PS_NULL)
+            ok(ext_pen.elp.elpPenStyle == pen[i].ret_style, "expected %x, got %lx\n", pen[i].ret_style, ext_pen.elp.elpPenStyle);
+        else
         {
-            /* for some reason XP differenciates PS_NULL here */
-            if (pen[i].style == PS_NULL)
-                ok(ext_pen.elp.elpPenStyle == pen[i].ret_style, "expected %x, got %lx\n", pen[i].ret_style, ext_pen.elp.elpPenStyle);
-            else if (pen[i].style == PS_USERSTYLE) /* this time it's really PS_USERSTYLE */
-                ok(ext_pen.elp.elpPenStyle == (PS_GEOMETRIC | PS_USERSTYLE), "expected %x, got %lx\n", PS_GEOMETRIC | PS_USERSTYLE, ext_pen.elp.elpPenStyle);
-            else
-                ok(ext_pen.elp.elpPenStyle == (PS_GEOMETRIC | pen[i].ret_style), "expected %x, got %lx\n", PS_GEOMETRIC | pen[i].ret_style, ext_pen.elp.elpPenStyle);
-
-            if (pen[i].style == PS_NULL)
-                ok(ext_pen.elp.elpWidth == 0, "expected %u, got %lx\n", pen[i].ret_width, ext_pen.elp.elpWidth);
-            else
-                ok(ext_pen.elp.elpWidth == pen[i].ret_width, "expected %u, got %lx\n", pen[i].ret_width, ext_pen.elp.elpWidth);
-            ok(ext_pen.elp.elpColor == pen[i].ret_color, "expected %08lx, got %08lx\n", pen[i].ret_color, ext_pen.elp.elpColor);
-            ok(ext_pen.elp.elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %x\n", ext_pen.elp.elpBrushStyle);
+if (pen[i].style == PS_USERSTYLE)
+{
+    todo_wine
+            ok(ext_pen.elp.elpPenStyle == (PS_GEOMETRIC | pen[i].style), "expected %x, got %lx\n", PS_GEOMETRIC | pen[i].style, ext_pen.elp.elpPenStyle);
+}
+else
+            ok(ext_pen.elp.elpPenStyle == (PS_GEOMETRIC | pen[i].style), "expected %x, got %lx\n", PS_GEOMETRIC | pen[i].style, ext_pen.elp.elpPenStyle);
         }
 
+        if (pen[i].style == PS_NULL)
+            ok(ext_pen.elp.elpWidth == 0, "expected 0, got %lx\n", ext_pen.elp.elpWidth);
+        else
+            ok(ext_pen.elp.elpWidth == pen[i].ret_width, "expected %u, got %lx\n", pen[i].ret_width, ext_pen.elp.elpWidth);
+        ok(ext_pen.elp.elpColor == pen[i].ret_color, "expected %08lx, got %08lx\n", pen[i].ret_color, ext_pen.elp.elpColor);
+        ok(ext_pen.elp.elpBrushStyle == BS_SOLID, "expected BS_SOLID, got %x\n", ext_pen.elp.elpBrushStyle);
+
         DeleteObject(hpen);
     }
 }
diff --git a/dlls/wineps/pen.c b/dlls/wineps/pen.c
index 64ad7e5..590acaf 100644
--- a/dlls/wineps/pen.c
+++ b/dlls/wineps/pen.c
@@ -41,7 +41,20 @@
 {
     LOGPEN logpen;
 
-    if (!GetObjectA( hpen, sizeof(logpen), &logpen )) return 0;
+    if (!GetObjectW( hpen, sizeof(logpen), &logpen ))
+    {
+        /* must be an extended pen */
+        EXTLOGPEN elp;
+        if (!GetObjectW( hpen, sizeof(elp), &elp ))
+        {
+            FIXME("extended pen %p not supported\n", hpen);
+            return 0;
+        }
+        logpen.lopnStyle = elp.elpPenStyle;
+        logpen.lopnWidth.x = elp.elpWidth;
+        logpen.lopnWidth.y = 0;
+        logpen.lopnColor = elp.elpColor;
+    }
 
     TRACE("hpen = %p colour = %08lx\n", hpen, logpen.lopnColor);
 
diff --git a/dlls/x11drv/pen.c b/dlls/x11drv/pen.c
index a23cd48..2db5136 100644
--- a/dlls/x11drv/pen.c
+++ b/dlls/x11drv/pen.c
@@ -38,7 +38,20 @@
 {
     LOGPEN logpen;
 
-    if (!GetObjectA( hpen, sizeof(logpen), &logpen )) return 0;
+    if (!GetObjectW( hpen, sizeof(logpen), &logpen ))
+    {
+        /* must be an extended pen */
+        EXTLOGPEN elp;
+        if (!GetObjectW( hpen, sizeof(elp), &elp ))
+        {
+            FIXME("extended pen %p not supported\n", hpen);
+            return 0;
+        }
+        logpen.lopnStyle = elp.elpPenStyle;
+        logpen.lopnWidth.x = elp.elpWidth;
+        logpen.lopnWidth.y = 0;
+        logpen.lopnColor = elp.elpColor;
+    }
 
     physDev->pen.style = logpen.lopnStyle & PS_STYLE_MASK;
     physDev->pen.type = logpen.lopnStyle & PS_TYPE_MASK;
diff --git a/include/gdi.h b/include/gdi.h
index af18a03..91beab3 100644
--- a/include/gdi.h
+++ b/include/gdi.h
@@ -44,7 +44,8 @@
 #define ENHMETAFILE_MAGIC     0x4f52
 #define ENHMETAFILE_DC_MAGIC  0x4f53
 #define MEMORY_DC_MAGIC       0x4f54
-#define LAST_MAGIC            0x4f54
+#define EXT_PEN_MAGIC         0x4f55
+#define LAST_MAGIC            0x4f55
 
 #define MAGIC_DONTCARE	      0xffff