[PATCH 4/4] comctl32/button: Use allocated structure to keep control data

Nikolay Sivov nsivov at codeweavers.com
Thu Feb 15 02:00:09 CST 2018


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---

It's not only to match what Windows does, it will make it easier to store
additional data once BCM_* messages support is implemented.

 dlls/comctl32/button.c       | 354 +++++++++++++++++++++----------------------
 dlls/comctl32/tests/button.c |   4 +
 2 files changed, 175 insertions(+), 183 deletions(-)

diff --git a/dlls/comctl32/button.c b/dlls/comctl32/button.c
index 6458ba1444..d7a47cb9a7 100644
--- a/dlls/comctl32/button.c
+++ b/dlls/comctl32/button.c
@@ -73,12 +73,6 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(button);
 
-/* GetWindowLong offsets for window extra information */
-#define STATE_GWL_OFFSET  0
-#define HFONT_GWL_OFFSET  (sizeof(LONG))
-#define HIMAGE_GWL_OFFSET (HFONT_GWL_OFFSET+sizeof(HFONT))
-#define NB_EXTRA_BYTES    (HIMAGE_GWL_OFFSET+sizeof(HANDLE))
-
 /* undocumented flags */
 #define BUTTON_NSTATES         0x0F
 #define BUTTON_BTNPRESSED      0x40
@@ -93,12 +87,25 @@ WINE_DEFAULT_DEBUG_CHANNEL(button);
                      (LPARAM)(hWnd)); \
     } while(0)
 
-static UINT BUTTON_CalcLabelRect( HWND hwnd, HDC hdc, RECT *rc );
-static void PB_Paint( HWND hwnd, HDC hDC, UINT action );
-static void CB_Paint( HWND hwnd, HDC hDC, UINT action );
-static void GB_Paint( HWND hwnd, HDC hDC, UINT action );
-static void UB_Paint( HWND hwnd, HDC hDC, UINT action );
-static void OB_Paint( HWND hwnd, HDC hDC, UINT action );
+typedef struct _BUTTON_INFO
+{
+    HWND        hwnd;
+    LONG        state;
+    HFONT       font;
+    union
+    {
+        HICON   icon;
+        HBITMAP bitmap;
+        HANDLE  image;
+    } u;
+} BUTTON_INFO;
+
+static UINT BUTTON_CalcLabelRect( const BUTTON_INFO *infoPtr, HDC hdc, RECT *rc );
+static void PB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action );
+static void CB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action );
+static void GB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action );
+static void UB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action );
+static void OB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action );
 static void BUTTON_CheckAutoRadioButton( HWND hwnd );
 
 #define MAX_BTN_TYPE  16
@@ -133,7 +140,7 @@ typedef enum
     STATE_DEFAULTED
 } ButtonState;
 
-typedef void (*pfPaint)( HWND hwnd, HDC hdc, UINT action );
+typedef void (*pfPaint)( const BUTTON_INFO *infoPtr, HDC hdc, UINT action );
 
 static const pfPaint btnPaintFunc[MAX_BTN_TYPE] =
 {
@@ -155,11 +162,11 @@ static const pfPaint btnPaintFunc[MAX_BTN_TYPE] =
     PB_Paint     /* BS_DEFCOMMANDLINK */
 };
 
-typedef void (*pfThemedPaint)( HTHEME theme, HWND hwnd, HDC hdc, ButtonState drawState, UINT dtflags, BOOL focused);
+typedef void (*pfThemedPaint)( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc, ButtonState drawState, UINT dtflags, BOOL focused);
 
-static void PB_ThemedPaint( HTHEME theme, HWND hwnd, HDC hdc, ButtonState drawState, UINT dtflags, BOOL focused);
-static void CB_ThemedPaint( HTHEME theme, HWND hwnd, HDC hdc, ButtonState drawState, UINT dtflags, BOOL focused);
-static void GB_ThemedPaint( HTHEME theme, HWND hwnd, HDC hdc, ButtonState drawState, UINT dtflags, BOOL focused);
+static void PB_ThemedPaint( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc, ButtonState drawState, UINT dtflags, BOOL focused);
+static void CB_ThemedPaint( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc, ButtonState drawState, UINT dtflags, BOOL focused);
+static void GB_ThemedPaint( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc, ButtonState drawState, UINT dtflags, BOOL focused);
 
 static const pfThemedPaint btnThemedPaintFunc[MAX_BTN_TYPE] =
 {
@@ -181,53 +188,29 @@ static const pfThemedPaint btnThemedPaintFunc[MAX_BTN_TYPE] =
     NULL,           /* BS_DEFCOMMANDLINK */
 };
 
-/*********************************************************************
- * button class descriptor
- */
-
-static inline LONG get_button_state( HWND hwnd )
-{
-    return GetWindowLongW( hwnd, STATE_GWL_OFFSET );
-}
-
-static inline void set_button_state( HWND hwnd, LONG state )
-{
-    SetWindowLongW( hwnd, STATE_GWL_OFFSET, state );
-}
-
-static inline HFONT get_button_font( HWND hwnd )
-{
-    return (HFONT)GetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET );
-}
-
-static inline void set_button_font( HWND hwnd, HFONT font )
-{
-    SetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET, (LONG_PTR)font );
-}
-
 static inline UINT get_button_type( LONG window_style )
 {
     return (window_style & BS_TYPEMASK);
 }
 
 /* paint a button of any type */
-static inline void paint_button( HWND hwnd, LONG style, UINT action )
+static inline void paint_button( BUTTON_INFO *infoPtr, LONG style, UINT action )
 {
-    if (btnPaintFunc[style] && IsWindowVisible(hwnd))
+    if (btnPaintFunc[style] && IsWindowVisible(infoPtr->hwnd))
     {
-        HDC hdc = GetDC( hwnd );
-        btnPaintFunc[style]( hwnd, hdc, action );
-        ReleaseDC( hwnd, hdc );
+        HDC hdc = GetDC( infoPtr->hwnd );
+        btnPaintFunc[style]( infoPtr, hdc, action );
+        ReleaseDC( infoPtr->hwnd, hdc );
     }
 }
 
 /* retrieve the button text; returned buffer must be freed by caller */
-static inline WCHAR *get_button_text( HWND hwnd )
+static inline WCHAR *get_button_text( const BUTTON_INFO *infoPtr )
 {
-    INT len = GetWindowTextLengthW( hwnd );
+    INT len = GetWindowTextLengthW( infoPtr->hwnd );
     WCHAR *buffer = heap_alloc( (len + 1) * sizeof(WCHAR) );
     if (buffer)
-        GetWindowTextW( hwnd, buffer, len + 1 );
+        GetWindowTextW( infoPtr->hwnd, buffer, len + 1 );
     return buffer;
 }
 
@@ -300,9 +283,9 @@ static UINT BUTTON_BStoDT( DWORD style, DWORD ex_style )
     return dtStyle;
 }
 
-
 static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
+    BUTTON_INFO *infoPtr = (BUTTON_INFO *)GetWindowLongPtrW(hWnd, 0);
     RECT rect;
     POINT pt;
     LONG style = GetWindowLongW( hWnd, GWL_STYLE );
@@ -313,6 +296,9 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
 
     if (!IsWindow( hWnd )) return 0;
 
+    if (!infoPtr && (uMsg != WM_NCCREATE))
+        return DefWindowProcW(hWnd, uMsg, wParam, lParam);
+
     pt.x = (short)LOWORD(lParam);
     pt.y = (short)HIWORD(lParam);
 
@@ -339,7 +325,18 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
         if (theme)
             RedrawWindow( hWnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW );
         else
-            paint_button( hWnd, btn_type, ODA_DRAWENTIRE );
+            paint_button( infoPtr, btn_type, ODA_DRAWENTIRE );
+        break;
+
+    case WM_NCCREATE:
+        infoPtr = heap_alloc_zero( sizeof(*infoPtr) );
+        SetWindowLongPtrW( hWnd, 0, (LONG_PTR)infoPtr );
+        infoPtr->hwnd = hWnd;
+        return DefWindowProcW(hWnd, uMsg, wParam, lParam);
+
+    case WM_NCDESTROY:
+        SetWindowLongPtrW( hWnd, 0, 0 );
+        heap_free(infoPtr);
         break;
 
     case WM_CREATE:
@@ -352,7 +349,7 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
             style = (style & ~BS_TYPEMASK) | BS_PUSHBUTTON;
             SetWindowLongW( hWnd, GWL_STYLE, style );
         }
-        set_button_state( hWnd, BST_UNCHECKED );
+        infoPtr->state = BST_UNCHECKED;
         OpenThemeData( hWnd, WC_BUTTONW );
         return 0;
 
@@ -398,24 +395,23 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
             ButtonState drawState;
             UINT dtflags;
 
-            state = get_button_state( hWnd );
             if (IsWindowEnabled( hWnd ))
             {
-                if (state & BST_PUSHED) drawState = STATE_PRESSED;
-                else if (state & BST_HOT) drawState = STATE_HOT;
-                else if (state & BST_FOCUS) drawState = STATE_DEFAULTED;
+                if (infoPtr->state & BST_PUSHED) drawState = STATE_PRESSED;
+                else if (infoPtr->state & BST_HOT) drawState = STATE_HOT;
+                else if (infoPtr->state & BST_FOCUS) drawState = STATE_DEFAULTED;
                 else drawState = STATE_NORMAL;
             }
             else
                 drawState = STATE_DISABLED;
 
             dtflags = BUTTON_BStoDT(style, GetWindowLongW(hWnd, GWL_EXSTYLE));
-            btnThemedPaintFunc[btn_type](theme, hWnd, hdc, drawState, dtflags, state & BST_FOCUS);
+            btnThemedPaintFunc[btn_type](theme, infoPtr, hdc, drawState, dtflags, infoPtr->state & BST_FOCUS);
         }
         else if (btnPaintFunc[btn_type])
         {
             int nOldMode = SetBkMode( hdc, OPAQUE );
-            (btnPaintFunc[btn_type])( hWnd, hdc, ODA_DRAWENTIRE );
+            btnPaintFunc[btn_type]( infoPtr, hdc, ODA_DRAWENTIRE );
             SetBkMode(hdc, nOldMode); /*  reset painting mode */
         }
 
@@ -427,7 +423,7 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
 	if (wParam == VK_SPACE)
 	{
 	    SendMessageW( hWnd, BM_SETSTATE, TRUE, 0 );
-            set_button_state( hWnd, get_button_state( hWnd ) | BUTTON_BTNPRESSED );
+            infoPtr->state |= BUTTON_BTNPRESSED;
             SetCapture( hWnd );
 	}
 	break;
@@ -445,7 +441,7 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
     case WM_LBUTTONDOWN:
         SetCapture( hWnd );
         SetFocus( hWnd );
-        set_button_state( hWnd, get_button_state( hWnd ) | BUTTON_BTNPRESSED );
+        infoPtr->state |= BUTTON_BTNPRESSED;
         SendMessageW( hWnd, BM_SETSTATE, TRUE, 0 );
         break;
 
@@ -454,10 +450,9 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
 	    break;
 	/* fall through */
     case WM_LBUTTONUP:
-        state = get_button_state( hWnd );
+        state = infoPtr->state;
         if (!(state & BUTTON_BTNPRESSED)) break;
-        state &= BUTTON_NSTATES;
-        set_button_state( hWnd, state );
+        infoPtr->state &= BUTTON_NSTATES;
         if (!(state & BST_PUSHED))
         {
             ReleaseCapture();
@@ -467,18 +462,17 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
         GetClientRect( hWnd, &rect );
 	if (uMsg == WM_KEYUP || PtInRect( &rect, pt ))
         {
-            state = get_button_state( hWnd );
             switch(btn_type)
             {
             case BS_AUTOCHECKBOX:
-                SendMessageW( hWnd, BM_SETCHECK, !(state & BST_CHECKED), 0 );
+                SendMessageW( hWnd, BM_SETCHECK, !(infoPtr->state & BST_CHECKED), 0 );
                 break;
             case BS_AUTORADIOBUTTON:
                 SendMessageW( hWnd, BM_SETCHECK, TRUE, 0 );
                 break;
             case BS_AUTO3STATE:
-                SendMessageW( hWnd, BM_SETCHECK,
-                                (state & BST_INDETERMINATE) ? 0 : ((state & 3) + 1), 0 );
+                SendMessageW( hWnd, BM_SETCHECK, (infoPtr->state & BST_INDETERMINATE) ? 0 :
+                    ((infoPtr->state & 3) + 1), 0 );
                 break;
             }
             ReleaseCapture();
@@ -493,12 +487,11 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
     case WM_CAPTURECHANGED:
         TRACE("WM_CAPTURECHANGED %p\n", hWnd);
         if (hWnd == (HWND)lParam) break;
-        state = get_button_state( hWnd );
-        if (state & BUTTON_BTNPRESSED)
+        if (infoPtr->state & BUTTON_BTNPRESSED)
         {
-            state &= BUTTON_NSTATES;
-            set_button_state( hWnd, state );
-            if (state & BST_PUSHED) SendMessageW( hWnd, BM_SETSTATE, FALSE, 0 );
+            infoPtr->state &= BUTTON_NSTATES;
+            if (infoPtr->state & BST_PUSHED)
+                SendMessageW( hWnd, BM_SETSTATE, FALSE, 0 );
         }
         break;
 
@@ -526,14 +519,14 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
 
     case WM_MOUSEHOVER:
     {
-        set_button_state( hWnd, get_button_state( hWnd ) | BST_HOT );
+        infoPtr->state |= BST_HOT;
         InvalidateRect( hWnd, NULL, FALSE );
         break;
     }
 
     case WM_MOUSELEAVE:
     {
-        set_button_state( hWnd, get_button_state( hWnd ) & ~BST_HOT );
+        infoPtr->state &= ~BST_HOT;
         InvalidateRect( hWnd, NULL, FALSE );
         break;
     }
@@ -565,7 +558,7 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
             /* FIXME: check other BS_* handlers */
             if (btn_type == BS_GROUPBOX)
                 InflateRect(&rc, -7, 1); /* GB_Paint does this */
-            BUTTON_CalcLabelRect(hWnd, hdc, &rc);
+            BUTTON_CalcLabelRect(infoPtr, hdc, &rc);
             /* Clip by client rect bounds */
             if (rc.right > client.right) rc.right = client.right;
             if (rc.bottom > client.bottom) rc.bottom = client.bottom;
@@ -577,33 +570,32 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
         if (btn_type == BS_GROUPBOX) /* Yes, only for BS_GROUPBOX */
             InvalidateRect( hWnd, NULL, TRUE );
         else
-            paint_button( hWnd, btn_type, ODA_DRAWENTIRE );
+            paint_button( infoPtr, btn_type, ODA_DRAWENTIRE );
         return 1; /* success. FIXME: check text length */
     }
 
     case WM_SETFONT:
-        set_button_font( hWnd, (HFONT)wParam );
+        infoPtr->font = (HFONT)wParam;
         if (lParam) InvalidateRect(hWnd, NULL, TRUE);
         break;
 
     case WM_GETFONT:
-        return (LRESULT)get_button_font( hWnd );
+        return (LRESULT)infoPtr->font;
 
     case WM_SETFOCUS:
         TRACE("WM_SETFOCUS %p\n",hWnd);
-        set_button_state( hWnd, get_button_state(hWnd) | BST_FOCUS );
-        paint_button( hWnd, btn_type, ODA_FOCUS );
+        infoPtr->state |= BST_FOCUS;
+        paint_button( infoPtr, btn_type, ODA_FOCUS );
         if (style & BS_NOTIFY)
             BUTTON_NOTIFY_PARENT(hWnd, BN_SETFOCUS);
         break;
 
     case WM_KILLFOCUS:
         TRACE("WM_KILLFOCUS %p\n",hWnd);
-        state = get_button_state( hWnd );
-        set_button_state( hWnd, state & ~BST_FOCUS );
-	paint_button( hWnd, btn_type, ODA_FOCUS );
+        infoPtr->state &= ~BST_FOCUS;
+        paint_button( infoPtr, btn_type, ODA_FOCUS );
 
-        if ((state & BUTTON_BTNPRESSED) && GetCapture() == hWnd)
+        if ((infoPtr->state & BUTTON_BTNPRESSED) && GetCapture() == hWnd)
             ReleaseCapture();
         if (style & BS_NOTIFY)
             BUTTON_NOTIFY_PARENT(hWnd, BN_KILLFOCUS);
@@ -644,27 +636,27 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
         default:
             return 0;
         }
-        oldHbitmap = (HBITMAP)SetWindowLongPtrW( hWnd, HIMAGE_GWL_OFFSET, lParam );
+        oldHbitmap = infoPtr->u.image;
+        infoPtr->u.image = (HANDLE)lParam;
 	InvalidateRect( hWnd, NULL, FALSE );
 	return (LRESULT)oldHbitmap;
 
     case BM_GETIMAGE:
-        return GetWindowLongPtrW( hWnd, HIMAGE_GWL_OFFSET );
+        return (LRESULT)infoPtr->u.image;
 
     case BM_GETCHECK:
-        return get_button_state( hWnd ) & 3;
+        return infoPtr->state & 3;
 
     case BM_SETCHECK:
         if (wParam > maxCheckState[btn_type]) wParam = maxCheckState[btn_type];
-        state = get_button_state( hWnd );
         if ((btn_type == BS_RADIOBUTTON) || (btn_type == BS_AUTORADIOBUTTON))
         {
             style = wParam ? style | WS_TABSTOP : style & ~WS_TABSTOP;
             SetWindowLongW( hWnd, GWL_STYLE, style );
         }
-        if ((state & 3) != wParam)
+        if ((infoPtr->state & 3) != wParam)
         {
-            set_button_state( hWnd, (state & ~3) | wParam );
+            infoPtr->state = (infoPtr->state & ~3) | wParam;
             InvalidateRect( hWnd, NULL, FALSE );
         }
         if ((btn_type == BS_AUTORADIOBUTTON) && (wParam == BST_CHECKED) && (style & WS_CHILD))
@@ -672,10 +664,10 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
         break;
 
     case BM_GETSTATE:
-        return get_button_state( hWnd );
+        return infoPtr->state;
 
     case BM_SETSTATE:
-        state = get_button_state( hWnd );
+        state = infoPtr->state;
         new_state = wParam ? BST_PUSHED : 0;
 
         if ((state ^ new_state) & BST_PUSHED)
@@ -687,7 +679,7 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
 
             if (btn_type == BS_USERBUTTON)
                 BUTTON_NOTIFY_PARENT( hWnd, (state & BST_PUSHED) ? BN_HILITE : BN_UNHILITE );
-            set_button_state( hWnd, state );
+            infoPtr->state = state;
 
             InvalidateRect( hWnd, NULL, FALSE );
         }
@@ -712,10 +704,10 @@ static LRESULT CALLBACK BUTTON_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
  * (pushed, etc.). If there is nothing to draw (no text/image) output
  * rectangle is empty, and return value is (UINT)-1.
  */
-static UINT BUTTON_CalcLabelRect(HWND hwnd, HDC hdc, RECT *rc)
+static UINT BUTTON_CalcLabelRect(const BUTTON_INFO *infoPtr, HDC hdc, RECT *rc)
 {
-   LONG style = GetWindowLongW( hwnd, GWL_STYLE );
-   LONG ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
+   LONG style = GetWindowLongW( infoPtr->hwnd, GWL_STYLE );
+   LONG ex_style = GetWindowLongW( infoPtr->hwnd, GWL_EXSTYLE );
    WCHAR *text;
    ICONINFO    iconInfo;
    BITMAP      bm;
@@ -730,14 +722,14 @@ static UINT BUTTON_CalcLabelRect(HWND hwnd, HDC hdc, RECT *rc)
       {
           HFONT hFont, hPrevFont = 0;
 
-          if (!(text = get_button_text( hwnd ))) goto empty_rect;
+          if (!(text = get_button_text( infoPtr ))) goto empty_rect;
           if (!text[0])
           {
               heap_free( text );
               goto empty_rect;
           }
 
-          if ((hFont = get_button_font( hwnd ))) hPrevFont = SelectObject( hdc, hFont );
+          if ((hFont = infoPtr->font)) hPrevFont = SelectObject( hdc, hFont );
           DrawTextW(hdc, text, -1, &r, dtStyle | DT_CALCRECT);
           if (hPrevFont) SelectObject( hdc, hPrevFont );
           heap_free( text );
@@ -745,7 +737,7 @@ static UINT BUTTON_CalcLabelRect(HWND hwnd, HDC hdc, RECT *rc)
       }
 
       case BS_ICON:
-         if (!GetIconInfo((HICON)GetWindowLongPtrW( hwnd, HIMAGE_GWL_OFFSET ), &iconInfo))
+         if (!GetIconInfo(infoPtr->u.icon, &iconInfo))
             goto empty_rect;
 
          GetObjectW (iconInfo.hbmColor, sizeof(BITMAP), &bm);
@@ -758,7 +750,7 @@ static UINT BUTTON_CalcLabelRect(HWND hwnd, HDC hdc, RECT *rc)
          break;
 
       case BS_BITMAP:
-         if (!GetObjectW( (HANDLE)GetWindowLongPtrW( hwnd, HIMAGE_GWL_OFFSET ), sizeof(BITMAP), &bm))
+         if (!GetObjectW( infoPtr->u.bitmap, sizeof(BITMAP), &bm))
             goto empty_rect;
 
          r.right  = r.left + bm.bmWidth;
@@ -826,15 +818,15 @@ static BOOL CALLBACK BUTTON_DrawTextCallback(HDC hdc, LPARAM lp, WPARAM wp, int
  *
  *   Common function for drawing button label.
  */
-static void BUTTON_DrawLabel(HWND hwnd, HDC hdc, UINT dtFlags, const RECT *rc)
+static void BUTTON_DrawLabel(const BUTTON_INFO *infoPtr, HDC hdc, UINT dtFlags, const RECT *rc)
 {
    DRAWSTATEPROC lpOutputProc = NULL;
    LPARAM lp;
    WPARAM wp = 0;
    HBRUSH hbr = 0;
-   UINT flags = IsWindowEnabled(hwnd) ? DSS_NORMAL : DSS_DISABLED;
-   LONG state = get_button_state( hwnd );
-   LONG style = GetWindowLongW( hwnd, GWL_STYLE );
+   UINT flags = IsWindowEnabled(infoPtr->hwnd) ? DSS_NORMAL : DSS_DISABLED;
+   LONG state = infoPtr->state;
+   LONG style = GetWindowLongW( infoPtr->hwnd, GWL_STYLE );
    WCHAR *text = NULL;
 
    /* FIXME: To draw disabled label in Win31 look-and-feel, we probably
@@ -853,19 +845,19 @@ static void BUTTON_DrawLabel(HWND hwnd, HDC hdc, UINT dtFlags, const RECT *rc)
       case BS_TEXT:
          /* DST_COMPLEX -- is 0 */
          lpOutputProc = BUTTON_DrawTextCallback;
-         if (!(text = get_button_text( hwnd ))) return;
+         if (!(text = get_button_text( infoPtr ))) return;
          lp = (LPARAM)text;
          wp = dtFlags;
          break;
 
       case BS_ICON:
          flags |= DST_ICON;
-         lp = GetWindowLongPtrW( hwnd, HIMAGE_GWL_OFFSET );
+         lp = (LPARAM)infoPtr->u.icon;
          break;
 
       case BS_BITMAP:
          flags |= DST_BITMAP;
-         lp = GetWindowLongPtrW( hwnd, HIMAGE_GWL_OFFSET );
+         lp = (LPARAM)infoPtr->u.bitmap;
          break;
 
       default:
@@ -880,7 +872,7 @@ static void BUTTON_DrawLabel(HWND hwnd, HDC hdc, UINT dtFlags, const RECT *rc)
 /**********************************************************************
  *       Push Button Functions
  */
-static void PB_Paint( HWND hwnd, HDC hDC, UINT action )
+static void PB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
 {
     RECT     rc, r;
     UINT     dtFlags, uState;
@@ -889,19 +881,19 @@ static void PB_Paint( HWND hwnd, HDC hDC, UINT action )
     INT      oldBkMode;
     COLORREF oldTxtColor;
     HFONT hFont;
-    LONG state = get_button_state( hwnd );
-    LONG style = GetWindowLongW( hwnd, GWL_STYLE );
+    LONG state = infoPtr->state;
+    LONG style = GetWindowLongW( infoPtr->hwnd, GWL_STYLE );
     BOOL pushedState = (state & BST_PUSHED);
     HWND parent;
     HRGN hrgn;
 
-    GetClientRect( hwnd, &rc );
+    GetClientRect( infoPtr->hwnd, &rc );
 
     /* Send WM_CTLCOLOR to allow changing the font (the colors are fixed) */
-    if ((hFont = get_button_font( hwnd ))) SelectObject( hDC, hFont );
-    parent = GetParent(hwnd);
-    if (!parent) parent = hwnd;
-    SendMessageW( parent, WM_CTLCOLORBTN, (WPARAM)hDC, (LPARAM)hwnd );
+    if ((hFont = infoPtr->font)) SelectObject( hDC, hFont );
+    parent = GetParent(infoPtr->hwnd);
+    if (!parent) parent = infoPtr->hwnd;
+    SendMessageW( parent, WM_CTLCOLORBTN, (WPARAM)hDC, (LPARAM)infoPtr->hwnd );
 
     hrgn = set_control_clipping( hDC, &rc );
 
@@ -939,7 +931,7 @@ static void PB_Paint( HWND hwnd, HDC hDC, UINT action )
 
     /* draw button label */
     r = rc;
-    dtFlags = BUTTON_CalcLabelRect(hwnd, hDC, &r);
+    dtFlags = BUTTON_CalcLabelRect(infoPtr, hDC, &r);
 
     if (dtFlags == (UINT)-1L)
        goto cleanup;
@@ -949,7 +941,7 @@ static void PB_Paint( HWND hwnd, HDC hDC, UINT action )
 
     oldTxtColor = SetTextColor( hDC, GetSysColor(COLOR_BTNTEXT) );
 
-    BUTTON_DrawLabel(hwnd, hDC, dtFlags, &r);
+    BUTTON_DrawLabel(infoPtr, hDC, dtFlags, &r);
 
     SetTextColor( hDC, oldTxtColor );
 
@@ -973,42 +965,40 @@ draw_focus:
  *       Check Box & Radio Button Functions
  */
 
-static void CB_Paint( HWND hwnd, HDC hDC, UINT action )
+static void CB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
 {
     RECT rbox, rtext, client;
     HBRUSH hBrush;
     int delta, text_offset, checkBoxWidth, checkBoxHeight;
     UINT dtFlags;
     HFONT hFont;
-    LONG state = get_button_state( hwnd );
-    LONG style = GetWindowLongW( hwnd, GWL_STYLE );
-    LONG ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
+    LONG state = infoPtr->state;
+    LONG style = GetWindowLongW( infoPtr->hwnd, GWL_STYLE );
+    LONG ex_style = GetWindowLongW( infoPtr->hwnd, GWL_EXSTYLE );
     HWND parent;
     HRGN hrgn;
 
     if (style & BS_PUSHLIKE)
     {
-        PB_Paint( hwnd, hDC, action );
+        PB_Paint( infoPtr, hDC, action );
 	return;
     }
 
-    GetClientRect(hwnd, &client);
+    GetClientRect(infoPtr->hwnd, &client);
     rbox = rtext = client;
 
     checkBoxWidth  = 12 * GetDeviceCaps( hDC, LOGPIXELSX ) / 96 + 1;
     checkBoxHeight = 12 * GetDeviceCaps( hDC, LOGPIXELSY ) / 96 + 1;
 
-    if ((hFont = get_button_font( hwnd ))) SelectObject( hDC, hFont );
+    if ((hFont = infoPtr->font)) SelectObject( hDC, hFont );
     GetCharWidthW( hDC, '0', '0', &text_offset );
     text_offset /= 2;
 
-    parent = GetParent(hwnd);
-    if (!parent) parent = hwnd;
-    hBrush = (HBRUSH)SendMessageW(parent, WM_CTLCOLORSTATIC,
-				  (WPARAM)hDC, (LPARAM)hwnd);
+    parent = GetParent(infoPtr->hwnd);
+    if (!parent) parent = infoPtr->hwnd;
+    hBrush = (HBRUSH)SendMessageW(parent, WM_CTLCOLORSTATIC, (WPARAM)hDC, (LPARAM)infoPtr->hwnd);
     if (!hBrush) /* did the app forget to call defwindowproc ? */
-        hBrush = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORSTATIC,
-					(WPARAM)hDC, (LPARAM)hwnd );
+        hBrush = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORSTATIC, (WPARAM)hDC, (LPARAM)infoPtr->hwnd);
     hrgn = set_control_clipping( hDC, &client );
 
     if (style & BS_LEFTTEXT || ex_style & WS_EX_RIGHT)
@@ -1028,7 +1018,7 @@ static void CB_Paint( HWND hwnd, HDC hDC, UINT action )
 
     /* Draw label */
     client = rtext;
-    dtFlags = BUTTON_CalcLabelRect(hwnd, hDC, &rtext);
+    dtFlags = BUTTON_CalcLabelRect(infoPtr, hDC, &rtext);
 
     /* Only adjust rbox when rtext is valid */
     if (dtFlags != (UINT)-1L)
@@ -1088,7 +1078,7 @@ static void CB_Paint( HWND hwnd, HDC hDC, UINT action )
 	return;
 
     if (action == ODA_DRAWENTIRE)
-	BUTTON_DrawLabel(hwnd, hDC, dtFlags, &rtext);
+        BUTTON_DrawLabel(infoPtr, hDC, dtFlags, &rtext);
 
     /* ... and focus */
     if (action == ODA_FOCUS || (state & BST_FOCUS))
@@ -1130,26 +1120,25 @@ static void BUTTON_CheckAutoRadioButton( HWND hwnd )
  *       Group Box Functions
  */
 
-static void GB_Paint( HWND hwnd, HDC hDC, UINT action )
+static void GB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
 {
     RECT rc, rcFrame;
     HBRUSH hbr;
     HFONT hFont;
     UINT dtFlags;
     TEXTMETRICW tm;
-    LONG style = GetWindowLongW( hwnd, GWL_STYLE );
+    LONG style = GetWindowLongW( infoPtr->hwnd, GWL_STYLE );
     HWND parent;
     HRGN hrgn;
 
-    if ((hFont = get_button_font( hwnd ))) SelectObject( hDC, hFont );
+    if ((hFont = infoPtr->font)) SelectObject( hDC, hFont );
     /* GroupBox acts like static control, so it sends CTLCOLORSTATIC */
-    parent = GetParent(hwnd);
-    if (!parent) parent = hwnd;
-    hbr = (HBRUSH)SendMessageW(parent, WM_CTLCOLORSTATIC, (WPARAM)hDC, (LPARAM)hwnd);
+    parent = GetParent(infoPtr->hwnd);
+    if (!parent) parent = infoPtr->hwnd;
+    hbr = (HBRUSH)SendMessageW(parent, WM_CTLCOLORSTATIC, (WPARAM)hDC, (LPARAM)infoPtr->hwnd);
     if (!hbr) /* did the app forget to call defwindowproc ? */
-        hbr = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORSTATIC,
-				     (WPARAM)hDC, (LPARAM)hwnd);
-    GetClientRect( hwnd, &rc);
+        hbr = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORSTATIC, (WPARAM)hDC, (LPARAM)infoPtr->hwnd);
+    GetClientRect( infoPtr->hwnd, &rc);
     rcFrame = rc;
     hrgn = set_control_clipping( hDC, &rc );
 
@@ -1158,7 +1147,7 @@ static void GB_Paint( HWND hwnd, HDC hDC, UINT action )
     DrawEdge (hDC, &rcFrame, EDGE_ETCHED, BF_RECT | ((style & BS_FLAT) ? BF_FLAT : 0));
 
     InflateRect(&rc, -7, 1);
-    dtFlags = BUTTON_CalcLabelRect(hwnd, hDC, &rc);
+    dtFlags = BUTTON_CalcLabelRect(infoPtr, hDC, &rc);
 
     if (dtFlags != (UINT)-1)
     {
@@ -1172,7 +1161,7 @@ static void GB_Paint( HWND hwnd, HDC hDC, UINT action )
         FillRect(hDC, &rc, hbr);
         rc.left++; rc.right--; rc.bottom--;
 
-        BUTTON_DrawLabel(hwnd, hDC, dtFlags, &rc);
+        BUTTON_DrawLabel(infoPtr, hDC, dtFlags, &rc);
     }
     SelectClipRgn( hDC, hrgn );
     if (hrgn) DeleteObject( hrgn );
@@ -1183,24 +1172,23 @@ static void GB_Paint( HWND hwnd, HDC hDC, UINT action )
  *       User Button Functions
  */
 
-static void UB_Paint( HWND hwnd, HDC hDC, UINT action )
+static void UB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
 {
     RECT rc;
     HBRUSH hBrush;
     HFONT hFont;
-    LONG state = get_button_state( hwnd );
+    LONG state = infoPtr->state;
     HWND parent;
 
-    GetClientRect( hwnd, &rc);
+    GetClientRect( infoPtr->hwnd, &rc);
 
-    if ((hFont = get_button_font( hwnd ))) SelectObject( hDC, hFont );
+    if ((hFont = infoPtr->font)) SelectObject( hDC, hFont );
 
-    parent = GetParent(hwnd);
-    if (!parent) parent = hwnd;
-    hBrush = (HBRUSH)SendMessageW(parent, WM_CTLCOLORBTN, (WPARAM)hDC, (LPARAM)hwnd);
+    parent = GetParent(infoPtr->hwnd);
+    if (!parent) parent = infoPtr->hwnd;
+    hBrush = (HBRUSH)SendMessageW(parent, WM_CTLCOLORBTN, (WPARAM)hDC, (LPARAM)infoPtr->hwnd);
     if (!hBrush) /* did the app forget to call defwindowproc ? */
-        hBrush = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORBTN,
-					(WPARAM)hDC, (LPARAM)hwnd);
+        hBrush = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORBTN, (WPARAM)hDC, (LPARAM)infoPtr->hwnd);
 
     FillRect( hDC, &rc, hBrush );
     if (action == ODA_FOCUS || (state & BST_FOCUS))
@@ -1209,11 +1197,11 @@ static void UB_Paint( HWND hwnd, HDC hDC, UINT action )
     switch (action)
     {
     case ODA_FOCUS:
-        BUTTON_NOTIFY_PARENT( hwnd, (state & BST_FOCUS) ? BN_SETFOCUS : BN_KILLFOCUS );
+        BUTTON_NOTIFY_PARENT( infoPtr->hwnd, (state & BST_FOCUS) ? BN_SETFOCUS : BN_KILLFOCUS );
         break;
 
     case ODA_SELECT:
-        BUTTON_NOTIFY_PARENT( hwnd, (state & BST_PUSHED) ? BN_HILITE : BN_UNHILITE );
+        BUTTON_NOTIFY_PARENT( infoPtr->hwnd, (state & BST_PUSHED) ? BN_HILITE : BN_UNHILITE );
         break;
 
     default:
@@ -1226,11 +1214,11 @@ static void UB_Paint( HWND hwnd, HDC hDC, UINT action )
  *       Ownerdrawn Button Functions
  */
 
-static void OB_Paint( HWND hwnd, HDC hDC, UINT action )
+static void OB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
 {
-    LONG state = get_button_state( hwnd );
+    LONG state = infoPtr->state;
     DRAWITEMSTRUCT dis;
-    LONG_PTR id = GetWindowLongPtrW( hwnd, GWLP_ID );
+    LONG_PTR id = GetWindowLongPtrW( infoPtr->hwnd, GWLP_ID );
     HWND parent;
     HFONT hFont, hPrevFont = 0;
     HRGN hrgn;
@@ -1241,40 +1229,40 @@ static void OB_Paint( HWND hwnd, HDC hDC, UINT action )
     dis.itemAction = action;
     dis.itemState  = ((state & BST_FOCUS) ? ODS_FOCUS : 0) |
                      ((state & BST_PUSHED) ? ODS_SELECTED : 0) |
-                     (IsWindowEnabled(hwnd) ? 0: ODS_DISABLED);
-    dis.hwndItem   = hwnd;
+                     (IsWindowEnabled(infoPtr->hwnd) ? 0: ODS_DISABLED);
+    dis.hwndItem   = infoPtr->hwnd;
     dis.hDC        = hDC;
     dis.itemData   = 0;
-    GetClientRect( hwnd, &dis.rcItem );
+    GetClientRect( infoPtr->hwnd, &dis.rcItem );
 
-    if ((hFont = get_button_font( hwnd ))) hPrevFont = SelectObject( hDC, hFont );
-    parent = GetParent(hwnd);
-    if (!parent) parent = hwnd;
-    SendMessageW( parent, WM_CTLCOLORBTN, (WPARAM)hDC, (LPARAM)hwnd );
+    if ((hFont = infoPtr->font)) hPrevFont = SelectObject( hDC, hFont );
+    parent = GetParent(infoPtr->hwnd);
+    if (!parent) parent = infoPtr->hwnd;
+    SendMessageW( parent, WM_CTLCOLORBTN, (WPARAM)hDC, (LPARAM)infoPtr->hwnd );
 
     hrgn = set_control_clipping( hDC, &dis.rcItem );
 
-    SendMessageW( GetParent(hwnd), WM_DRAWITEM, id, (LPARAM)&dis );
+    SendMessageW( GetParent(infoPtr->hwnd), WM_DRAWITEM, id, (LPARAM)&dis );
     if (hPrevFont) SelectObject(hDC, hPrevFont);
     SelectClipRgn( hDC, hrgn );
     if (hrgn) DeleteObject( hrgn );
 }
 
-static void PB_ThemedPaint(HTHEME theme, HWND hwnd, HDC hDC, ButtonState drawState, UINT dtFlags, BOOL focused)
+static void PB_ThemedPaint(HTHEME theme, const BUTTON_INFO *infoPtr, HDC hDC, ButtonState drawState, UINT dtFlags, BOOL focused)
 {
     static const int states[] = { PBS_NORMAL, PBS_DISABLED, PBS_HOT, PBS_PRESSED, PBS_DEFAULTED };
 
     RECT bgRect, textRect;
-    HFONT font = get_button_font( hwnd );
+    HFONT font = infoPtr->font;
     HFONT hPrevFont = font ? SelectObject(hDC, font) : NULL;
     int state = states[ drawState ];
-    WCHAR *text = get_button_text(hwnd);
+    WCHAR *text = get_button_text(infoPtr);
 
-    GetClientRect(hwnd, &bgRect);
+    GetClientRect(infoPtr->hwnd, &bgRect);
     GetThemeBackgroundContentRect(theme, hDC, BP_PUSHBUTTON, state, &bgRect, &textRect);
 
     if (IsThemeBackgroundPartiallyTransparent(theme, BP_PUSHBUTTON, state))
-        DrawThemeParentBackground(hwnd, hDC, NULL);
+        DrawThemeParentBackground(infoPtr->hwnd, hDC, NULL);
     DrawThemeBackground(theme, hDC, BP_PUSHBUTTON, state, &bgRect, NULL);
     if (text)
     {
@@ -1300,7 +1288,7 @@ static void PB_ThemedPaint(HTHEME theme, HWND hwnd, HDC hDC, ButtonState drawSta
     if (hPrevFont) SelectObject(hDC, hPrevFont);
 }
 
-static void CB_ThemedPaint(HTHEME theme, HWND hwnd, HDC hDC, ButtonState drawState, UINT dtFlags, BOOL focused)
+static void CB_ThemedPaint(HTHEME theme, const BUTTON_INFO *infoPtr, HDC hDC, ButtonState drawState, UINT dtFlags, BOOL focused)
 {
     static const int cb_states[3][5] =
     {
@@ -1318,14 +1306,14 @@ static void CB_ThemedPaint(HTHEME theme, HWND hwnd, HDC hDC, ButtonState drawSta
     SIZE sz;
     RECT bgRect, textRect;
     HFONT font, hPrevFont = NULL;
-    int checkState = get_button_state( hwnd ) & 3;
-    DWORD dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
+    int checkState = infoPtr->state & 3;
+    DWORD dwStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
     UINT btn_type = get_button_type( dwStyle );
     int part = (btn_type == BS_RADIOBUTTON) || (btn_type == BS_AUTORADIOBUTTON) ? BP_RADIOBUTTON : BP_CHECKBOX;
     int state = (part == BP_CHECKBOX)
               ? cb_states[ checkState ][ drawState ]
               : rb_states[ checkState ][ drawState ];
-    WCHAR *text = get_button_text(hwnd);
+    WCHAR *text = get_button_text(infoPtr);
     LOGFONTW lf;
     BOOL created_font = FALSE;
 
@@ -1340,14 +1328,14 @@ static void CB_ThemedPaint(HTHEME theme, HWND hwnd, HDC hDC, ButtonState drawSta
             created_font = TRUE;
         }
     } else {
-        font = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0);
+        font = (HFONT)SendMessageW(infoPtr->hwnd, WM_GETFONT, 0, 0);
         hPrevFont = SelectObject(hDC, font);
     }
 
     if (FAILED(GetThemePartSize(theme, hDC, part, state, NULL, TS_DRAW, &sz)))
         sz.cx = sz.cy = 13;
 
-    GetClientRect(hwnd, &bgRect);
+    GetClientRect(infoPtr->hwnd, &bgRect);
     GetThemeBackgroundContentRect(theme, hDC, part, state, &bgRect, &textRect);
 
     if (dtFlags & DT_SINGLELINE) /* Center the checkbox / radio button to the text. */
@@ -1358,7 +1346,7 @@ static void CB_ThemedPaint(HTHEME theme, HWND hwnd, HDC hDC, ButtonState drawSta
     bgRect.right = bgRect.left + sz.cx;
     textRect.left = bgRect.right + 6;
 
-    DrawThemeParentBackground(hwnd, hDC, NULL);
+    DrawThemeParentBackground(infoPtr->hwnd, hDC, NULL);
 
     DrawThemeBackground(theme, hDC, part, state, &bgRect, NULL);
     if (text)
@@ -1386,13 +1374,13 @@ static void CB_ThemedPaint(HTHEME theme, HWND hwnd, HDC hDC, ButtonState drawSta
     if (hPrevFont) SelectObject(hDC, hPrevFont);
 }
 
-static void GB_ThemedPaint(HTHEME theme, HWND hwnd, HDC hDC, ButtonState drawState, UINT dtFlags, BOOL focused)
+static void GB_ThemedPaint(HTHEME theme, const BUTTON_INFO *infoPtr, HDC hDC, ButtonState drawState, UINT dtFlags, BOOL focused)
 {
     static const int states[] = { GBS_NORMAL, GBS_DISABLED, GBS_NORMAL, GBS_NORMAL, GBS_NORMAL };
 
     RECT bgRect, textRect, contentRect;
     int state = states[ drawState ];
-    WCHAR *text = get_button_text(hwnd);
+    WCHAR *text = get_button_text(infoPtr);
     LOGFONTW lf;
     HFONT font, hPrevFont = NULL;
     BOOL created_font = FALSE;
@@ -1407,11 +1395,11 @@ static void GB_ThemedPaint(HTHEME theme, HWND hwnd, HDC hDC, ButtonState drawSta
             created_font = TRUE;
         }
     } else {
-        font = (HFONT)SendMessageW(hwnd, WM_GETFONT, 0, 0);
+        font = (HFONT)SendMessageW(infoPtr->hwnd, WM_GETFONT, 0, 0);
         hPrevFont = SelectObject(hDC, font);
     }
 
-    GetClientRect(hwnd, &bgRect);
+    GetClientRect(infoPtr->hwnd, &bgRect);
     textRect = bgRect;
 
     if (text)
@@ -1430,7 +1418,7 @@ static void GB_ThemedPaint(HTHEME theme, HWND hwnd, HDC hDC, ButtonState drawSta
     ExcludeClipRect(hDC, contentRect.left, contentRect.top, contentRect.right, contentRect.bottom);
 
     if (IsThemeBackgroundPartiallyTransparent(theme, BP_GROUPBOX, state))
-        DrawThemeParentBackground(hwnd, hDC, NULL);
+        DrawThemeParentBackground(infoPtr->hwnd, hDC, NULL);
     DrawThemeBackground(theme, hDC, BP_GROUPBOX, state, &bgRect, NULL);
 
     SelectClipRgn(hDC, NULL);
@@ -1454,7 +1442,7 @@ void BUTTON_Register(void)
     wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW | CS_PARENTDC;
     wndClass.lpfnWndProc = BUTTON_WindowProc;
     wndClass.cbClsExtra = 0;
-    wndClass.cbWndExtra = NB_EXTRA_BYTES;
+    wndClass.cbWndExtra = sizeof(BUTTON_INFO *);
     wndClass.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
     wndClass.hbrBackground = NULL;
     wndClass.lpszClassName = WC_BUTTONW;
diff --git a/dlls/comctl32/tests/button.c b/dlls/comctl32/tests/button.c
index 47aee3f622..45a390d7f7 100644
--- a/dlls/comctl32/tests/button.c
+++ b/dlls/comctl32/tests/button.c
@@ -729,10 +729,14 @@ static void test_button_class(void)
     ret = GetClassInfoExA(NULL, WC_BUTTONA, &exA);
     ok(ret, "got %d\n", ret);
     ok(IS_WNDPROC_HANDLE(exA.lpfnWndProc), "got %p\n", exA.lpfnWndProc);
+    ok(exA.cbClsExtra == 0, "Unexpected class bytes %d.\n", exA.cbClsExtra);
+    ok(exA.cbWndExtra == sizeof(void *), "Unexpected window bytes %d.\n", exA.cbWndExtra);
 
     ret = GetClassInfoExW(NULL, WC_BUTTONW, &exW);
     ok(ret, "got %d\n", ret);
     ok(!IS_WNDPROC_HANDLE(exW.lpfnWndProc), "got %p\n", exW.lpfnWndProc);
+    ok(exW.cbClsExtra == 0, "Unexpected class bytes %d.\n", exW.cbClsExtra);
+    ok(exW.cbWndExtra == sizeof(void *), "Unexpected window bytes %d.\n", exW.cbWndExtra);
 
     /* check that versioned class is also accessible */
     nameW = get_versioned_classname(WC_BUTTONW);
-- 
2.15.1




More information about the wine-devel mailing list