update for HEAD-2003091401
[reactos.git] / lib / user32 / windows / draw.c
index 6713bbc..40f446b 100644 (file)
 
 #include <windows.h>
 #include <user32.h>
+
+// Needed for DrawState
+#include <string.h>
+#include <unicode.h>
+#include <draw.h>
+
+#define NDEBUG
 #include <debug.h>
 
 /* GLOBALS *******************************************************************/
@@ -469,7 +476,7 @@ static BOOL UITOOLS95_DrawRectEdge(HDC hdc, LPRECT rc,
         * middle (COLOR_BTNFACE). I believe it's the same for win95 but since
         * I don't know I go with Bertho and just sets it for win98 until proven
         * otherwise.
-        *                                          Dennis Björklund, 10 June, 99
+        *                                          Dennis Björklund, 10 June, 99
         */
 /*     if( TWEAK_WineLook == WIN98_LOOK && LTInnerI != -1 ) */
             LTInnerI = RBInnerI = COLOR_BTNFACE;
@@ -520,13 +527,13 @@ static BOOL UITOOLS95_DrawRectEdge(HDC hdc, LPRECT rc,
     SelectObject(hdc, RBOuterPen);
     if(uFlags & BF_BOTTOM)
     {
-        MoveToEx(hdc, InnerRect.right, InnerRect.bottom-1, NULL);
-        LineTo(hdc, InnerRect.left, InnerRect.bottom-1);
+        MoveToEx(hdc, InnerRect.left, InnerRect.bottom-1, NULL);
+        LineTo(hdc, InnerRect.right, InnerRect.bottom-1);
     }
     if(uFlags & BF_RIGHT)
     {
-        MoveToEx(hdc, InnerRect.right-1, InnerRect.bottom, NULL);
-        LineTo(hdc, InnerRect.right-1, InnerRect.top);
+        MoveToEx(hdc, InnerRect.right-1, InnerRect.top, NULL);
+        LineTo(hdc, InnerRect.right-1, InnerRect.bottom);
     }
 
     /* Draw the inner edge */
@@ -544,13 +551,13 @@ static BOOL UITOOLS95_DrawRectEdge(HDC hdc, LPRECT rc,
     SelectObject(hdc, RBInnerPen);
     if(uFlags & BF_BOTTOM)
     {
-        MoveToEx(hdc, InnerRect.right-RBpenplus, InnerRect.bottom-2, NULL);
-        LineTo(hdc, InnerRect.left+LBpenplus, InnerRect.bottom-2);
+        MoveToEx(hdc, InnerRect.left+LBpenplus, InnerRect.bottom-2, NULL);
+        LineTo(hdc, InnerRect.right-RBpenplus, InnerRect.bottom-2);
     }
     if(uFlags & BF_RIGHT)
     {
-        MoveToEx(hdc, InnerRect.right-2, InnerRect.bottom-RBpenplus, NULL);
-        LineTo(hdc, InnerRect.right-2, InnerRect.top+RTpenplus);
+        MoveToEx(hdc, InnerRect.right-2, InnerRect.top+RTpenplus, NULL);
+        LineTo(hdc, InnerRect.right-2, InnerRect.bottom-RBpenplus);
     }
 
     if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) )
@@ -890,8 +897,7 @@ static BOOL UITOOLS95_DrawFrameCaption(HDC dc, LPRECT r, UINT uFlags)
     COLORREF clrsave;
     SIZE size;
 
-    //UITOOLS95_DFC_ButtonPush(dc, r, uFlags & 0xff00);
-    if(uFlags & DFCS_PUSHED)
+  if(uFlags & DFCS_PUSHED)
       UITOOLS95_DrawRectEdge(dc,r,EDGE_SUNKEN, BF_RECT | BF_MIDDLE | BF_SOFT);
     else
       UITOOLS95_DrawRectEdge(dc,r,BDR_RAISEDINNER | BDR_RAISEDOUTER, BF_RECT |
@@ -938,6 +944,7 @@ static BOOL UITOOLS95_DrawFrameCaption(HDC dc, LPRECT r, UINT uFlags)
                        start.y++;
         }
 
+        /* now use the width of each line */
         width -= numLines - 1;
 
         for (i = 0; i < numLines; i++)
@@ -945,12 +952,11 @@ static BOOL UITOOLS95_DrawFrameCaption(HDC dc, LPRECT r, UINT uFlags)
             MoveToEx(dc, start.x + i, start.y, &oldPos);
             LineTo(dc, start.x + i + width, start.y + height);
 
-            MoveToEx(dc, start.x + i, start.y + height, &oldPos);
-            LineTo(dc, start.x + i + width, start.y);
+            MoveToEx(dc, start.x + i, start.y + height - 1, &oldPos);
+            LineTo(dc, start.x + i + width, start.y - 1);
         }
 
         SelectObject(dc, hpsave);
-        
         return TRUE;
     }
 
@@ -959,8 +965,8 @@ static BOOL UITOOLS95_DrawFrameCaption(HDC dc, LPRECT r, UINT uFlags)
         /* FIXME: We need the Marlett font in order to get this right. */
 
         hf = CreateFontA(-SmallDiam, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
-                         ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
-                         DEFAULT_QUALITY, FIXED_PITCH|FF_DONTCARE, "System");
+                        ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+                        DEFAULT_QUALITY, FIXED_PITCH|FF_DONTCARE, "System");
         alignsave = SetTextAlign(dc, TA_TOP|TA_LEFT);
         bksave = SetBkMode(dc, TRANSPARENT);
         clrsave = GetTextColor(dc);
@@ -1038,12 +1044,13 @@ static BOOL UITOOLS95_DrawFrameCaption(HDC dc, LPRECT r, UINT uFlags)
         break;
 
     default:
-        DbgPrint("Invalid caption; flags=0x%04x\n", uFlags);
         return FALSE;
     }
 
+    /* Here the drawing takes place */
     if(uFlags & DFCS_INACTIVE)
     {
+        /* If we have an inactive button, then you see a shadow */
         hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
         hpsave = (HPEN)SelectObject(dc, GetSysColorPen(COLOR_BTNHIGHLIGHT));
         Polygon(dc, Line1, Line1N);
@@ -1053,6 +1060,7 @@ static BOOL UITOOLS95_DrawFrameCaption(HDC dc, LPRECT r, UINT uFlags)
         SelectObject(dc, hbsave);
     }
 
+    /* Correct for the shadow shift */
     if (!(uFlags & DFCS_PUSHED))
     {
         for(i = 0; i < Line1N; i++)
@@ -1067,6 +1075,7 @@ static BOOL UITOOLS95_DrawFrameCaption(HDC dc, LPRECT r, UINT uFlags)
         }
     }
 
+    /* Make the final picture */
     hbsave = (HBRUSH)SelectObject(dc, GetSysColorBrush(colorIdx));
     hpsave = (HPEN)SelectObject(dc, GetSysColorPen(colorIdx));
 
@@ -1079,8 +1088,6 @@ static BOOL UITOOLS95_DrawFrameCaption(HDC dc, LPRECT r, UINT uFlags)
     return TRUE;
 }
 
-/* Ported from WINE20020904 */
-/* Draw a scroll-bar control coming from DrawFrameControl() */
 static BOOL UITOOLS95_DrawFrameScroll(HDC dc, LPRECT r, UINT uFlags)
 {
     POINT Line[4];
@@ -1210,7 +1217,6 @@ static BOOL UITOOLS95_DrawFrameScroll(HDC dc, LPRECT r, UINT uFlags)
         return TRUE;
 
     default:
-        DbgPrint("Invalid scroll; flags=0x%04x\n", uFlags);
         return FALSE;
     }
 
@@ -1361,6 +1367,140 @@ BOOL WINAPI DrawEdge( HDC hdc, LPRECT rc, UINT edge, UINT flags )
       return UITOOLS95_DrawRectEdge(hdc, rc, edge, flags);
 }
 
+
+WINBOOL
+STDCALL
+INTERNAL_GrayString(
+  HDC hDC,
+  HBRUSH hBrush,
+  GRAYSTRINGPROC lpOutputFunc,
+  LPARAM lpData,
+  int nCount,
+  int X,
+  int Y,
+  int nWidth,
+  int nHeight,
+  BOOL unicode)
+{
+    // AG: Mostly implemented, but probably won't work properly or return
+    // correct error codes. I doubt it grays strings either... Untested!
+
+    BOOL    success = FALSE;
+    HDC     MemDC = NULL;
+    HBITMAP MemBMP = NULL,
+            OldBMP = NULL;
+    HBRUSH  OldBrush = NULL;
+    HFONT   OldFont = NULL;
+    RECT    r;
+    COLORREF ForeColor, BackColor;
+
+    ForeColor = SetTextColor(hDC, RGB(0, 0, 0));
+    BackColor = SetBkColor(hDC, RGB(255, 255, 255));
+
+    
+    if (! hBrush)
+    {
+        // The documentation is a little vague on what exactly should happen
+        // here. Something about using the same brush for window text???
+        hBrush = (HBRUSH) GetCurrentObject(hDC, OBJ_BRUSH);
+    }
+    
+    if ((nCount == -1) && (! lpOutputFunc))
+        return FALSE;
+    
+    if (! nCount)
+    {
+        // TODO: calculate the length (easy enough)
+        
+        if (unicode)
+            nCount = lstrlenW((WCHAR*)lpData);
+        else
+            nCount = strlen((CHAR*)lpData);
+    }
+
+    if (! nWidth || ! nHeight)
+    {
+        SIZE s;
+        // TODO: calculate the rect
+        
+        if (unicode)
+            success = GetTextExtentPoint32W(hDC, (WCHAR*) lpData, nCount, &s);
+        else
+            success = GetTextExtentPoint32A(hDC, (CHAR*) lpData, nCount, &s);
+
+        if (! success) goto cleanup;
+        
+        if (! nWidth)   nWidth = s.cx;
+        if (! nHeight)  nHeight = s.cy;
+    }
+
+    SetRect(&r, X, Y, X + nWidth, Y + nHeight);    
+
+    MemDC = CreateCompatibleDC(hDC);
+    if (! MemDC) goto cleanup;
+    MemBMP = CreateBitmap(nWidth, nHeight, 1, 1, NULL);
+    if (! MemBMP) goto cleanup;
+    OldBMP = SelectObject(MemDC, MemBMP);
+    if (! OldBMP) goto cleanup;
+    OldFont = SelectObject(MemDC, GetCurrentObject(hDC, OBJ_FONT));
+    if (! OldFont) goto cleanup;
+    OldBrush = SelectObject(MemDC, hBrush);
+    if (! OldBrush) goto cleanup;
+
+    if (! BitBlt(MemDC, 0, 0, nWidth, nHeight, hDC, X, Y, SRCCOPY)) goto cleanup;
+
+    SetTextColor(MemDC, RGB(255, 255, 255));
+    SetBkColor(MemDC, RGB(0, 0, 0));
+    
+    if (lpOutputFunc)
+    {
+        success = lpOutputFunc(MemDC, lpData, nCount); // Set brush etc first?
+        
+        if ((nCount == -1) && (! success))
+        {
+            // Don't gray (documented behaviour)
+            success = (BOOL) BitBlt(hDC, X, Y, nWidth, nHeight, MemDC, 0, 0, SRCCOPY);
+            goto cleanup;
+        }
+    }
+    else
+    {
+        if (unicode)
+            success = TextOutW(MemDC, 0, 0, (WCHAR*) lpData, nCount);
+        else
+            success = TextOutA(MemDC, 0, 0, (CHAR*) lpData, nCount);
+            
+        if (! success) goto cleanup;
+
+        PatBlt(MemDC, 0, 0, nWidth, nHeight, PATCOPY);
+//      This is how WINE does it: (but we should have our own graying brush already)
+//        hbsave = (HBRUSH)SelectObject(memdc, CACHE_GetPattern55AABrush());
+//        PatBlt(memdc, 0, 0, cx, cy, 0x000A0329);
+//        SelectObject(memdc, hbsave);
+    }
+
+    if (! BitBlt(hDC, X, Y, nWidth, nHeight, MemDC, 0, 0, SRCCOPY)) goto cleanup;
+
+    cleanup :
+        SetTextColor(hDC, ForeColor);
+        SetBkColor(hDC, BackColor);
+
+        if (MemDC)
+        {
+            if (OldFont) SelectObject(MemDC, OldFont);
+            if (OldBrush) SelectObject(MemDC, OldBrush);
+            if (OldBMP) SelectObject(MemDC, OldBMP);
+            if (MemBMP) DeleteObject(MemBMP);
+            DeleteDC(MemDC);
+        }
+
+        return success;
+}
+
+
+/*
+ * @implemented
+ */
 WINBOOL
 STDCALL
 GrayStringA(
@@ -1374,9 +1514,13 @@ GrayStringA(
   int nWidth,
   int nHeight)
 {
-  return FALSE;
+  return INTERNAL_GrayString(hDC, hBrush, lpOutputFunc, lpData, nCount, X, Y, nWidth, nHeight, FALSE);
 }
 
+
+/*
+ * @implemented
+ */
 WINBOOL
 STDCALL
 GrayStringW(
@@ -1390,16 +1534,28 @@ GrayStringW(
   int nWidth,
   int nHeight)
 {
-  return FALSE;
+  return INTERNAL_GrayString(hDC, hBrush, lpOutputFunc, lpData, nCount, X, Y, nWidth, nHeight, TRUE);
 }
+
+
+/*
+ * @implemented
+ */
 WINBOOL
 STDCALL
 InvertRect(
   HDC hDC,
   CONST RECT *lprc)
 {
-  return FALSE;
+  
+  return PatBlt(hDC, lprc->left, lprc->top, lprc->right - lprc->left,
+                       lprc->bottom - lprc->top, DSTINVERT);
 }
+
+
+/*
+ * @unimplemented
+ */
 LONG
 STDCALL
 TabbedTextOutA(
@@ -1412,9 +1568,14 @@ TabbedTextOutA(
   CONST LPINT lpnTabStopPositions,
   int nTabOrigin)
 {
+  UNIMPLEMENTED;
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 LONG
 STDCALL
 TabbedTextOutW(
@@ -1427,8 +1588,13 @@ TabbedTextOutW(
   CONST LPINT lpnTabStopPositions,
   int nTabOrigin)
 {
+  UNIMPLEMENTED;
   return 0;
 }
+
+/*
+ * @implemented
+ */
 int
 STDCALL
 FrameRect(
@@ -1436,25 +1602,52 @@ FrameRect(
   CONST RECT *lprc,
   HBRUSH hbr)
 {
-  return 0;
+HBRUSH oldbrush;
+RECT r = *lprc;
+
+       if ( (r.right <= r.left) || (r.bottom <= r.top) ) return 0;
+       if (!(oldbrush = SelectObject( hDC, hbr ))) return 0;
+        
+       PatBlt( hDC, r.left, r.top, 1, r.bottom - r.top, PATCOPY );
+       PatBlt( hDC, r.right - 1, r.top, 1, r.bottom - r.top, PATCOPY );
+       PatBlt( hDC, r.left, r.top, r.right - r.left, 1, PATCOPY );
+       PatBlt( hDC, r.left, r.bottom - 1, r.right - r.left, 1, PATCOPY );
+                                                                            
+       SelectObject( hDC, oldbrush );
+       return TRUE;
 }
+
+
+/*
+ * @unimplemented
+ */
 WINBOOL
 STDCALL
 FlashWindow(
   HWND hWnd,
   WINBOOL bInvert)
 {
+  UNIMPLEMENTED;
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL
 STDCALL
 FlashWindowEx(
   PFLASHWINFO pfwi)
 {
+  UNIMPLEMENTED;
   return FALSE;
 }
 
+
+/*
+ * @implemented
+ */
 int STDCALL
 FillRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr)
 {
@@ -1473,6 +1666,10 @@ FillRect(HDC hDC, CONST RECT *lprc, HBRUSH hbr)
   return(TRUE);
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL
 STDCALL
 DrawAnimatedRects(
@@ -1481,30 +1678,339 @@ DrawAnimatedRects(
   CONST RECT *lprcFrom,
   CONST RECT *lprcTo)
 {
+  UNIMPLEMENTED;
   return FALSE;
 }
 
-WINBOOL
-STDCALL
-DrawCaption(
-  HWND hwnd,
-  HDC hdc,
-  LPRECT lprc,
-  UINT uFlags)
-{
-  return FALSE;
-}
 
+/*
+ * @implemented
+ */
 WINBOOL
 STDCALL
 DrawFocusRect(
   HDC hDC,
   CONST RECT *lprc)
 {
-  return FALSE;
+    HBRUSH hOldBrush;
+    HPEN hOldPen, hNewPen;
+    INT oldDrawMode, oldBkMode;
+
+    hOldBrush = SelectObject(hDC, GetStockObject(NULL_BRUSH));
+    hNewPen = CreatePen(PS_ALTERNATE, 1, GetSysColor(COLOR_WINDOWTEXT));
+    hOldPen = SelectObject(hDC, hNewPen);
+    oldDrawMode = SetROP2(hDC, R2_XORPEN);
+    oldBkMode = SetBkMode(hDC, TRANSPARENT);
+
+    Rectangle(hDC, lprc->left, lprc->top, lprc->right, lprc->bottom);
+
+    SetBkMode(hDC, oldBkMode);
+    SetROP2(hDC, oldDrawMode);
+    SelectObject(hDC, hOldPen);
+    DeleteObject(hNewPen);
+    SelectObject(hDC, hOldBrush);
+
+    return TRUE;
+
 }
 
 
+// These are internal functions, based on the WINE sources. Currently they
+// are only implemented for DSS_NORMAL and DST_TEXT, although some handling
+// for DST_BITMAP has been included.
+
+WINBOOL INTERNAL_DrawStateDraw(HDC hdc, UINT type, DRAWSTATEPROC lpOutputFunc,
+                        LPARAM lData, WPARAM wData, LPRECT rc, UINT dtflags,
+                        BOOL unicode)
+{
+//    HDC MemDC;
+//    HBITMAP MemBMP;
+    BOOL retval = FALSE;
+    INT cx = rc->right - rc->left;
+    INT cy = rc->bottom - rc->top;
+
+//  Is this supposed to happen?
+//    if (((type == DST_TEXT) || (type == DST_PREFIXTEXT)) && (lpOutputFunc))
+//        type = DST_COMPLEX;
+
+    switch(type)
+    {
+        case DST_TEXT :
+        case DST_PREFIXTEXT :
+        {
+            DbgPrint("Drawing DST_TEXT\n");
+            if (unicode)
+                return DrawTextW(hdc, (LPWSTR)lData, (INT)wData, rc, dtflags);
+            else
+                return DrawTextA(hdc, (LPSTR)lData, (INT)wData, rc, dtflags);
+        }
+        
+        case DST_ICON :
+        {
+            // TODO
+            DbgPrint("Drawing DST_ICON\n");
+            return retval;
+        }
+        
+        case DST_BITMAP :
+        {
+            // TODO
+            DbgPrint("Drawing DST_BITMAP\n");
+            return retval;
+        }
+        
+        case DST_COMPLEX :
+        {
+            DbgPrint("Drawing DST_COMPLEX\n");
+            // Call lpOutputFunc, if necessary
+            if (lpOutputFunc)
+            {
+                // Something seems to be wrong with OffsetViewportOrgEx:
+                OffsetViewportOrgEx(hdc, rc->left, rc->top, NULL);
+                DbgPrint("Calling lpOutputFunc(0x%x, 0x%x, 0x%x, %d, %d)\n", hdc, lData, wData, cx, cy);
+                retval = lpOutputFunc(hdc, lData, wData, cx, cy);
+                OffsetViewportOrgEx(hdc, -rc->left, -rc->top, NULL);
+                return retval;
+            }
+            else
+                return FALSE;
+        }
+    }
+    
+    return FALSE;
+}
+
+
+WINBOOL INTERNAL_DrawState(
+  HDC hdc,
+  HBRUSH hbr,
+  DRAWSTATEPROC lpOutputFunc,
+  LPARAM lData,
+  WPARAM wData,
+  int x,
+  int y,
+  int cx,
+  int cy,
+  UINT fuFlags,
+  BOOL unicode)
+{
+    UINT type;
+    UINT state;
+    INT len;
+    RECT rect;
+    UINT dtflags = DT_NOCLIP;           // Flags for DrawText
+    BOOL retval = FALSE;                // Return value
+
+    COLORREF ForeColor,                 // Foreground color
+             BackColor;                 // Background color
+
+    HDC MemDC = NULL;                   // Memory DC
+    HBITMAP MemBMP = NULL,              // Memory bitmap (for MemDC)
+            OldBMP = NULL;              // Old memory bitmap (for MemDC)
+    HFONT   Font = NULL;                // Old font (for MemDC)
+    HBRUSH  OldBrush = NULL,            // Old brush (for MemDC)
+            TempBrush = NULL;           // Temporary brush (for MemDC)
+
+    // AG: Experimental, unfinished, and most likely buggy! I haven't been
+    // able to test this - my intention was to implement some things needed
+    // by the button control.
+
+    if ((! lpOutputFunc) && (fuFlags & DST_COMPLEX))
+        return FALSE;
+
+    type = fuFlags & 0xf;          // DST_xxx
+    state = fuFlags & 0x7ff0;      // DSS_xxx
+    len = wData;                    // Data length
+
+    DbgPrint("Entered DrawState, fuFlags %d, type %d, state %d\n", fuFlags, type, state);
+
+    if ((type == DST_TEXT || type == DST_PREFIXTEXT) && ! len)
+    {
+        // The string is NULL-terminated
+        if (unicode)
+            len = lstrlenW((LPWSTR) lData);
+        else
+            len = strlen((LPSTR) lData);
+    }
+    
+    // Identify the image size if not specified
+    if (!cx || !cy)
+    {
+        SIZE s;
+//        CURSORICONINFO *ici;
+        BITMAP bm;
+        
+        switch(type)  // TODO
+        {
+            case DST_TEXT :
+            case DST_PREFIXTEXT :
+            {
+                BOOL success;
+
+                DbgPrint("Calculating rect of DST_TEXT / DST_PREFIXTEXT\n");
+            
+                if (unicode)
+                    success = GetTextExtentPoint32W(hdc, (LPWSTR) lData, len, &s);
+                else
+                    success = GetTextExtentPoint32A(hdc, (LPSTR) lData, len, &s);
+
+                if (!success) return FALSE;
+                break;
+            }
+
+            case DST_ICON :
+            {
+                DbgPrint("Calculating rect of DST_ICON\n");
+                // TODO
+                break;
+            }
+
+            case DST_BITMAP :
+            {
+                DbgPrint("Calculating rect of DST_BITMAP\n");
+
+                if (!GetObjectA((HBITMAP) lData, sizeof(bm), &bm))
+                    return FALSE;
+                
+                s.cx = bm.bmWidth;
+                s.cy = bm.bmHeight;
+                break;
+            }
+
+            case DST_COMPLEX :  // cx and cy must be set in this mode
+                DbgPrint("Calculating rect of DST_COMPLEX - Not allowed!\n");
+                return FALSE;
+        }
+        
+        if (! cx) cx = s.cx;
+        if (! cy) cy = s.cy;
+    }
+
+    // Flags for DrawText
+    if (fuFlags & DSS_RIGHT)  // Undocumented
+        dtflags |= DT_RIGHT;
+    if (type == DST_TEXT)
+        dtflags |= DT_NOPREFIX;
+        
+    // No additional processing needed for DSS_NORMAL
+    if (state == DSS_NORMAL)
+    {
+        DbgPrint("DSS_NORMAL (no additional processing necessary)\n");
+        SetRect(&rect, x, y, x + cx, y + cy);
+        return INTERNAL_DrawStateDraw(hdc, type, lpOutputFunc, lData, wData, &rect, dtflags, unicode);
+    }
+    
+    // WARNING: FROM THIS POINT ON THE CODE IS VERY BUGGY
+
+    // Set the rectangle to that of the memory DC
+    SetRect(&rect, 0, 0, cx, cy);
+
+    // Set colors
+    ForeColor = SetTextColor(hdc, RGB(0, 0, 0));
+    BackColor = SetBkColor(hdc, RGB(255, 255, 255));
+
+    // Create and initialize the memory DC
+    MemDC = CreateCompatibleDC(hdc);
+    if (! MemDC) goto cleanup;
+    MemBMP = CreateBitmap(cx, cy, 1, 1, NULL);
+    if (! MemBMP) goto cleanup;
+    OldBMP = (HBITMAP) SelectObject(MemDC, MemBMP);
+    if (! OldBMP) goto cleanup;
+
+    DbgPrint("Created and inited MemDC\n");
+
+    // Set up the default colors and font
+    if (! FillRect(MemDC, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH))) goto cleanup;
+    SetBkColor(MemDC, RGB(255, 255, 255));
+    SetTextColor(MemDC, RGB(0, 0, 0));
+    Font = (HFONT)SelectObject(MemDC, GetCurrentObject(hdc, OBJ_FONT));
+
+    DbgPrint("Selected font and set colors\n");
+
+    // Enable this line to use the current DC image to begin with (wrong?)
+//    if (! BitBlt(MemDC, 0, 0, cx, cy, hdc, x, y, SRCCOPY)) goto cleanup;
+
+    // DST_COMPLEX may draw text as well, so make sure font is selected
+    if (! Font && (type <= DST_PREFIXTEXT)) // THIS FAILS
+      goto cleanup;
+
+    {
+      BOOL TempResult = INTERNAL_DrawStateDraw(MemDC, type, lpOutputFunc, lData, wData, &rect, dtflags, unicode);
+      if (Font) SelectObject(MemDC, Font);
+      if (! TempResult) goto cleanup;
+    }
+
+    DbgPrint("Done drawing\n");
+
+    // Apply state(s?)
+    if (state & DSS_UNION)
+    {
+        DbgPrint("DSS_UNION\n");
+        // Dither the image (not implemented in ReactOS yet?)
+        // TODO
+    }
+
+    // Prepare shadow brush
+    if (state & DSS_DISABLED)
+        TempBrush = CreateSolidBrush(GetSysColor(COLOR_3DHILIGHT));
+    // else if (state & DSS_DEFAULT)
+    // TempBrush = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
+
+    // Draw shadow
+    if (state & (DSS_DISABLED /*|DSS_DEFAULT*/))
+    {
+        DbgPrint("DSS_DISABLED - Drawing shadow\n");
+        if (! TempBrush) goto cleanup;
+        OldBrush = (HBRUSH)SelectObject(hdc, TempBrush);
+        if (! OldBrush) goto cleanup;
+        if (! BitBlt(hdc, x + 1, y + 1, cx, cy, MemDC, 0, 0, 0x00B8074A)) goto cleanup;
+        SelectObject(hdc, OldBrush);
+        DeleteObject(TempBrush);
+        TempBrush = NULL;
+    }
+
+    if (state & DSS_DISABLED)
+    {
+        DbgPrint("DSS_DISABLED - Creating shadow brush 2\n");
+        hbr = TempBrush = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
+        if (! TempBrush) goto cleanup;
+    }
+    else if (! hbr)
+    {
+        DbgPrint("Creating a brush\n");
+        hbr = (HBRUSH) GetStockObject(BLACK_BRUSH);
+    }
+    
+    DbgPrint("Selecting new brush\n");
+    OldBrush = (HBRUSH) SelectObject(hdc, hbr);
+
+    // Copy to hdc from MemDC    
+    DbgPrint("Blitting\n");
+    if (! BitBlt(hdc, x, y, cx, cy, MemDC, 0, 0, 0x00B8074A)) goto cleanup;
+    
+    retval = TRUE;
+
+    
+    cleanup :
+        DbgPrint("In cleanup : Font %x  OldBrush %x  OldBMP %x  Tempbrush %x  MemBMP %x  MemDC %x\n",
+                  Font, OldBrush, OldBMP, TempBrush, MemBMP, MemDC);
+        SetTextColor(hdc, ForeColor);
+        SetBkColor(hdc, BackColor);
+        if (OldBrush)   SelectObject(MemDC, OldBrush);
+        if (OldBMP)     SelectObject(MemDC, OldBMP);
+        if (TempBrush)  DeleteObject(TempBrush);
+        if (MemBMP)     DeleteObject(MemBMP);
+        if (MemDC)      DeleteDC(MemDC);
+        
+        DbgPrint("Leaving DrawState() with retval %d\n", retval);
+        
+        return retval;
+}
+
+
+/*
+ * @implemented
+ */
 WINBOOL
 STDCALL
 DrawStateA(
@@ -1519,9 +2025,13 @@ DrawStateA(
   int cy,
   UINT fuFlags)
 {
-  return FALSE;
+    return INTERNAL_DrawState(hdc, hbr, lpOutputFunc, lData, wData, x, y, cx, cy, fuFlags, FALSE);
 }
 
+
+/*
+ * @implemented
+ */
 WINBOOL
 STDCALL
 DrawStateW(
@@ -1536,5 +2046,5 @@ DrawStateW(
   int cy,
   UINT fuFlags)
 {
-  return FALSE;
+    return INTERNAL_DrawState(hdc, hbr, lpOutputFunc, lData, wData, x, y, cx, cy, fuFlags, TRUE);
 }