From ebbaf56bdb75f853dafdbbffba81233784ecb618 Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Sat, 4 May 2019 18:21:05 +0800
Subject: [PATCH 1/2] comctl32: Switch to using a structure for extra storage.
Content-Type: text/plain; charset=UTF-8
To: wine-devel@winehq.org

These patches aim to fix the bug 47018.

Signed-off-by: Dmitry Timoshkov <dmitry@baikal.ru>
---
 dlls/comctl32/static.c | 92 ++++++++++++++++++++++++++++++++++--------
 1 file changed, 76 insertions(+), 16 deletions(-)

diff --git a/dlls/comctl32/static.c b/dlls/comctl32/static.c
index 5cc02ced97..d08710c06f 100644
--- a/dlls/comctl32/static.c
+++ b/dlls/comctl32/static.c
@@ -36,6 +36,7 @@
 #include "winuser.h"
 #include "commctrl.h"
 
+#include "wine/heap.h"
 #include "wine/debug.h"
 
 #include "comctl32.h"
@@ -50,10 +51,16 @@ static void STATIC_PaintBitmapfn( HWND hwnd, HDC hdc, DWORD style );
 static void STATIC_PaintEnhMetafn( HWND hwnd, HDC hdc, DWORD style );
 static void STATIC_PaintEtchedfn( HWND hwnd, HDC hdc, DWORD style );
 
-/* offsets for GetWindowLong for static private information */
-#define HFONT_GWL_OFFSET    0
-#define HICON_GWL_OFFSET    (sizeof(HFONT))
-#define STATIC_EXTRA_BYTES  (HICON_GWL_OFFSET + sizeof(HICON))
+struct static_extra_info
+{
+    HFONT hfont;
+    union
+    {
+        HICON hicon;
+        HBITMAP hbitmap;
+        HENHMETAFILE hemf;
+    } image;
+};
 
 typedef void (*pfPaint)( HWND hwnd, HDC hdc, DWORD style );
 
@@ -80,6 +87,18 @@ static const pfPaint staticPaintFunc[SS_TYPEMASK+1] =
     STATIC_PaintEtchedfn,    /* SS_ETCHEDFRAME */
 };
 
+static struct static_extra_info *get_extra_ptr( HWND hwnd, BOOL force )
+{
+    struct static_extra_info *extra = (struct static_extra_info *)GetWindowLongPtrW( hwnd, 0 );
+    if (!extra && force)
+    {
+        extra = heap_alloc_zero( sizeof(*extra) );
+        if (extra)
+            SetWindowLongPtrW( hwnd, 0, (ULONG_PTR)extra );
+    }
+    return extra;
+}
+
 static BOOL get_icon_size( HICON handle, SIZE *size )
 {
     ICONINFO info;
@@ -111,6 +130,7 @@ static HICON STATIC_SetIcon( HWND hwnd, HICON hicon, DWORD style )
 {
     HICON prevIcon;
     SIZE size;
+    struct static_extra_info *extra;
 
     if ((style & SS_TYPEMASK) != SS_ICON) return 0;
     if (hicon && !get_icon_size( hicon, &size ))
@@ -118,7 +138,12 @@ static HICON STATIC_SetIcon( HWND hwnd, HICON hicon, DWORD style )
         WARN("hicon != 0, but invalid\n");
         return 0;
     }
-    prevIcon = (HICON)SetWindowLongPtrW( hwnd, HICON_GWL_OFFSET, (LONG_PTR)hicon );
+
+    extra = get_extra_ptr( hwnd, TRUE );
+    if (!extra) return 0;
+
+    prevIcon = extra->image.hicon;
+    extra->image.hicon = hicon;
     if (hicon && !(style & SS_CENTERIMAGE) && !(style & SS_REALSIZECONTROL))
     {
         /* Windows currently doesn't implement SS_RIGHTJUST */
@@ -146,6 +171,7 @@ static HICON STATIC_SetIcon( HWND hwnd, HICON hicon, DWORD style )
 static HBITMAP STATIC_SetBitmap( HWND hwnd, HBITMAP hBitmap, DWORD style )
 {
     HBITMAP hOldBitmap;
+    struct static_extra_info *extra;
 
     if ((style & SS_TYPEMASK) != SS_BITMAP) return 0;
     if (hBitmap && GetObjectType(hBitmap) != OBJ_BITMAP)
@@ -153,7 +179,12 @@ static HBITMAP STATIC_SetBitmap( HWND hwnd, HBITMAP hBitmap, DWORD style )
         WARN("hBitmap != 0, but it's not a bitmap\n");
         return 0;
     }
-    hOldBitmap = (HBITMAP)SetWindowLongPtrW( hwnd, HICON_GWL_OFFSET, (LONG_PTR)hBitmap );
+
+    extra = get_extra_ptr( hwnd, TRUE );
+    if (!extra) return 0;
+
+    hOldBitmap = extra->image.hbitmap;
+    extra->image.hbitmap = hBitmap;
     if (hBitmap && !(style & SS_CENTERIMAGE) && !(style & SS_REALSIZECONTROL))
     {
         BITMAP bm;
@@ -183,13 +214,23 @@ static HBITMAP STATIC_SetBitmap( HWND hwnd, HBITMAP hBitmap, DWORD style )
  */
 static HENHMETAFILE STATIC_SetEnhMetaFile( HWND hwnd, HENHMETAFILE hEnhMetaFile, DWORD style )
 {
+    HENHMETAFILE old_hemf;
+    struct static_extra_info *extra;
+
     if ((style & SS_TYPEMASK) != SS_ENHMETAFILE) return 0;
     if (hEnhMetaFile && GetObjectType(hEnhMetaFile) != OBJ_ENHMETAFILE)
     {
         WARN("hEnhMetaFile != 0, but it's not an enhanced metafile\n");
         return 0;
     }
-    return (HENHMETAFILE)SetWindowLongPtrW( hwnd, HICON_GWL_OFFSET, (LONG_PTR)hEnhMetaFile );
+
+    extra = get_extra_ptr( hwnd, TRUE );
+    if (!extra) return 0;
+
+    old_hemf = extra->image.hemf;
+    extra->image.hemf = hEnhMetaFile;
+
+    return old_hemf;
 }
 
 /***********************************************************************
@@ -200,6 +241,8 @@ static HENHMETAFILE STATIC_SetEnhMetaFile( HWND hwnd, HENHMETAFILE hEnhMetaFile,
  */
 static HANDLE STATIC_GetImage( HWND hwnd, WPARAM wParam, DWORD style )
 {
+    struct static_extra_info *extra;
+
     switch (style & SS_TYPEMASK)
     {
         case SS_ICON:
@@ -215,7 +258,22 @@ static HANDLE STATIC_GetImage( HWND hwnd, WPARAM wParam, DWORD style )
         default:
             return NULL;
     }
-    return (HANDLE)GetWindowLongPtrW( hwnd, HICON_GWL_OFFSET );
+
+    extra = get_extra_ptr( hwnd, FALSE );
+    return extra ? extra->image.hbitmap : 0;
+}
+
+static void STATIC_SetFont( HWND hwnd, HFONT hfont )
+{
+    struct static_extra_info *extra = get_extra_ptr( hwnd, TRUE );
+    if (extra)
+        extra->hfont = hfont;
+}
+
+static HFONT STATIC_GetFont( HWND hwnd )
+{
+    struct static_extra_info *extra = get_extra_ptr( hwnd, FALSE );
+    return extra ? extra->hfont : 0;
 }
 
 /***********************************************************************
@@ -327,6 +385,8 @@ static LRESULT CALLBACK STATIC_WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam,
     case WM_NCDESTROY:
         if (style == SS_ICON)
         {
+            struct static_extra_info *extra = get_extra_ptr( hwnd, FALSE );
+            heap_free( extra );
 /*
  * FIXME
  *           DestroyIcon32( STATIC_SetIcon( wndPtr, 0 ) );
@@ -423,14 +483,14 @@ static LRESULT CALLBACK STATIC_WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam,
     case WM_SETFONT:
         if (hasTextStyle( full_style ))
         {
-            SetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET, wParam );
+            STATIC_SetFont( hwnd, (HFONT)wParam );
             if (LOWORD(lParam))
                 RedrawWindow( hwnd, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN );
         }
         break;
 
     case WM_GETFONT:
-        return GetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET );
+        return (LRESULT)STATIC_GetFont( hwnd );
 
     case WM_NCHITTEST:
         if (full_style & SS_NOTIFY)
@@ -508,7 +568,7 @@ static void STATIC_PaintOwnerDrawfn( HWND hwnd, HDC hdc, DWORD style )
     dis.itemData   = 0;
     GetClientRect( hwnd, &dis.rcItem );
 
-    font = (HFONT)GetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET );
+    font = STATIC_GetFont( hwnd );
     if (font) oldFont = SelectObject( hdc, font );
     SendMessageW( GetParent(hwnd), WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hwnd );
     SendMessageW( GetParent(hwnd), WM_DRAWITEM, id, (LPARAM)&dis );
@@ -572,7 +632,7 @@ static void STATIC_PaintTextfn( HWND hwnd, HDC hdc, DWORD style )
             format |= DT_SINGLELINE | DT_WORD_ELLIPSIS;
     }
 
-    if ((hFont = (HFONT)GetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET )))
+    if ((hFont = STATIC_GetFont( hwnd )))
         hOldFont = SelectObject( hdc, hFont );
 
     /* SS_SIMPLE controls: WM_CTLCOLORSTATIC is sent, but the returned
@@ -668,7 +728,7 @@ static void STATIC_PaintIconfn( HWND hwnd, HDC hdc, DWORD style )
 
     GetClientRect( hwnd, &rc );
     hbrush = STATIC_SendWmCtlColorStatic(hwnd, hdc);
-    hIcon = (HICON)GetWindowLongPtrW( hwnd, HICON_GWL_OFFSET );
+    hIcon = STATIC_GetImage( hwnd, IMAGE_ICON, style );
     if (!hIcon || !get_icon_size( hIcon, &size ))
     {
         FillRect(hdc, &rc, hbrush);
@@ -698,7 +758,7 @@ static void STATIC_PaintBitmapfn(HWND hwnd, HDC hdc, DWORD style )
 
     hbrush = STATIC_SendWmCtlColorStatic(hwnd, hdc);
 
-    if ((hBitmap = (HBITMAP)GetWindowLongPtrW( hwnd, HICON_GWL_OFFSET ))
+    if ((hBitmap = STATIC_GetImage( hwnd, IMAGE_BITMAP, style ))
          && (GetObjectType(hBitmap) == OBJ_BITMAP)
          && (hMemDC = CreateCompatibleDC( hdc )))
     {
@@ -742,7 +802,7 @@ static void STATIC_PaintEnhMetafn(HWND hwnd, HDC hdc, DWORD style )
     GetClientRect(hwnd, &rc);
     hbrush = STATIC_SendWmCtlColorStatic(hwnd, hdc);
     FillRect(hdc, &rc, hbrush);
-    if ((hEnhMetaFile = (HENHMETAFILE)GetWindowLongPtrW( hwnd, HICON_GWL_OFFSET )))
+    if ((hEnhMetaFile = STATIC_GetImage( hwnd, IMAGE_ENHMETAFILE, style )))
     {
         /* The control's current font is not selected into the
            device context! */
@@ -779,7 +839,7 @@ void STATIC_Register(void)
     wndClass.style = CS_DBLCLKS | CS_PARENTDC | CS_GLOBALCLASS;
     wndClass.lpfnWndProc = STATIC_WindowProc;
     wndClass.cbClsExtra = 0;
-    wndClass.cbWndExtra = STATIC_EXTRA_BYTES;
+    wndClass.cbWndExtra = sizeof(struct static_extra_info *);
     wndClass.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
     wndClass.hbrBackground = NULL;
     wndClass.lpszClassName = WC_STATICW;
-- 
2.20.1

