[PATCH 2/5] win32u: Don't call CopyImage with user lock in set_class_long.

Jacek Caban wine at gitlab.winehq.org
Tue Jun 7 19:41:39 CDT 2022


From: Jacek Caban <jacek at codeweavers.com>

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
---
 dlls/win32u/class.c | 62 ++++++++++++++++++++++++++++++++++-----------
 1 file changed, 47 insertions(+), 15 deletions(-)

diff --git a/dlls/win32u/class.c b/dlls/win32u/class.c
index 320a1509a53..5af9e586e01 100644
--- a/dlls/win32u/class.c
+++ b/dlls/win32u/class.c
@@ -647,6 +647,7 @@ static BOOL set_server_info( HWND hwnd, INT offset, LONG_PTR newval, UINT size )
 static ULONG_PTR set_class_long( HWND hwnd, INT offset, LONG_PTR newval, UINT size, BOOL ansi )
 {
     ULONG_PTR retval = 0;
+    HICON small_icon = 0;
     CLASS *class;
 
     if (!(class = get_class_ptr( hwnd, TRUE ))) return 0;
@@ -696,31 +697,62 @@ static ULONG_PTR set_class_long( HWND hwnd, INT offset, LONG_PTR newval, UINT si
         break;
     case GCLP_HICON:
         retval = (ULONG_PTR)class->hIcon;
-        if (class->hIconSmIntern)
+        if (retval == newval) break;
+        if (newval && !class->hIconSm)
         {
-            NtUserDestroyCursor( class->hIconSmIntern, 0 );
-            class->hIconSmIntern = NULL;
+            release_class_ptr( class );
+
+            small_icon = CopyImage( (HICON)newval, IMAGE_ICON,
+                                    get_system_metrics( SM_CXSMICON ),
+                                    get_system_metrics( SM_CYSMICON ),
+                                    LR_COPYFROMRESOURCE );
+
+            if (!(class = get_class_ptr( hwnd, TRUE )))
+            {
+                NtUserDestroyCursor( small_icon, 0 );
+                return 0;
+            }
+            if (retval != HandleToUlong( class->hIcon ) || class->hIconSm)
+            {
+                /* someone beat us, restart */
+                release_class_ptr( class );
+                NtUserDestroyCursor( small_icon, 0 );
+                return set_class_long( hwnd, offset, newval, size, ansi );
+            }
         }
-        if (newval && !class->hIconSm)
-            class->hIconSmIntern = CopyImage( (HICON)newval, IMAGE_ICON,
-                                              get_system_metrics( SM_CXSMICON ),
-                                              get_system_metrics( SM_CYSMICON ),
-                                              LR_COPYFROMRESOURCE );
+        if (class->hIconSmIntern) NtUserDestroyCursor( class->hIconSmIntern, 0 );
         class->hIcon = (HICON)newval;
+        class->hIconSmIntern = small_icon;
         break;
     case GCLP_HICONSM:
         retval = (ULONG_PTR)class->hIconSm;
+        if (retval == newval) break;
         if (retval && !newval && class->hIcon)
-            class->hIconSmIntern = CopyImage( class->hIcon, IMAGE_ICON,
-                                              get_system_metrics( SM_CXSMICON ),
-                                              get_system_metrics( SM_CYSMICON ),
-                                              LR_COPYFROMRESOURCE );
-        else if (newval && class->hIconSmIntern)
         {
-            NtUserDestroyCursor( class->hIconSmIntern, 0 );
-            class->hIconSmIntern = NULL;
+            HICON icon = class->hIcon;
+            release_class_ptr( class );
+
+            small_icon = CopyImage( icon, IMAGE_ICON,
+                                    get_system_metrics( SM_CXSMICON ),
+                                    get_system_metrics( SM_CYSMICON ),
+                                    LR_COPYFROMRESOURCE );
+
+            if (!(class = get_class_ptr( hwnd, TRUE )))
+            {
+                NtUserDestroyCursor( small_icon, 0 );
+                return 0;
+            }
+            if (class->hIcon != icon || !class->hIconSm)
+            {
+                /* someone beat us, restart */
+                release_class_ptr( class );
+                NtUserDestroyCursor( small_icon, 0 );
+                return set_class_long( hwnd, offset, newval, size, ansi );
+            }
         }
+        if (class->hIconSmIntern) NtUserDestroyCursor( class->hIconSmIntern, 0 );
         class->hIconSm = (HICON)newval;
+        class->hIconSmIntern = small_icon;
         break;
     case GCL_STYLE:
         if (!set_server_info( hwnd, offset, newval, size )) break;
-- 
GitLab


https://gitlab.winehq.org/wine/wine/-/merge_requests/204



More information about the wine-devel mailing list