Jacek Caban : user32: Introduce NtUserSetCursorIconData.

Alexandre Julliard julliard at winehq.org
Tue Feb 22 16:06:51 CST 2022


Module: wine
Branch: master
Commit: f0176397adde8856c9149265121bd0b710c209cb
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=f0176397adde8856c9149265121bd0b710c209cb

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Tue Feb 22 13:41:40 2022 +0100

user32: Introduce NtUserSetCursorIconData.

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Huw Davies <huw at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/user32/cursoricon.c | 196 ++++++++++++++++++++++++++++++++++++-----------
 include/ntuser.h         |  15 ++++
 2 files changed, 168 insertions(+), 43 deletions(-)

diff --git a/dlls/user32/cursoricon.c b/dlls/user32/cursoricon.c
index b629e1412ae..556bc1b0f91 100644
--- a/dlls/user32/cursoricon.c
+++ b/dlls/user32/cursoricon.c
@@ -904,6 +904,123 @@ static const CURSORICONFILEDIRENTRY *CURSORICON_FindBestIconFile( const CURSORIC
     return &dir->idEntries[n];
 }
 
+static HICON alloc_cursoricon_handle( BOOL is_icon )
+{
+    struct cursoricon_object *obj;
+    HICON handle;
+
+    if (!(obj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*obj) ))) return NULL;
+    obj->is_icon = is_icon;
+
+    if (!(handle = alloc_user_handle( &obj->obj, NTUSER_OBJ_ICON ))) free( obj );
+    return handle;
+}
+
+/***********************************************************************
+ *	     NtUserSetCursorIconData (win32u.@)
+ */
+BOOL WINAPI NtUserSetCursorIconData( HCURSOR cursor, UNICODE_STRING *module, UNICODE_STRING *res_name,
+                                     struct cursoricon_desc *desc )
+{
+    struct cursoricon_object *obj;
+    UINT i, j;
+
+    if (!(obj = get_icon_ptr( cursor ))) return FALSE;
+
+    if (obj->is_ani || obj->frame.width)
+    {
+        /* already initialized */
+        release_user_handle_ptr( obj );
+        SetLastError( ERROR_INVALID_CURSOR_HANDLE );
+        return FALSE;
+    }
+
+    obj->delay = desc->delay;
+
+    if (desc->num_steps)
+    {
+        if (!(obj->ani.frames = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+                                           desc->num_steps * sizeof(*obj->ani.frames) )))
+        {
+            release_user_handle_ptr( obj );
+            return FALSE;
+        }
+        obj->is_ani = TRUE;
+        obj->ani.num_steps  = desc->num_steps;
+        obj->ani.num_frames = desc->num_frames;
+    }
+    else obj->frame = desc->frames[0];
+
+    if (!res_name)
+        obj->resname = NULL;
+    else if (res_name->Length)
+    {
+        obj->resname = HeapAlloc( GetProcessHeap(), 0, res_name->Length + sizeof(WCHAR) );
+        if (obj->resname)
+        {
+            memcpy( obj->resname, res_name->Buffer, res_name->Length );
+            obj->resname[res_name->Length / sizeof(WCHAR)] = 0;
+        }
+    }
+    else
+        obj->resname = MAKEINTRESOURCEW( LOWORD(res_name->Buffer) );
+
+    if (module && module->Length && (obj->module.Buffer = HeapAlloc( GetProcessHeap(), 0, module->Length )))
+    {
+        memcpy( obj->module.Buffer, module->Buffer, module->Length );
+        obj->module.Length = module->Length;
+    }
+
+    if (obj->is_ani)
+    {
+        /* Setup the animated frames in the correct sequence */
+        for (i = 0; i < desc->num_steps; i++)
+        {
+            struct cursoricon_desc frame_desc;
+            DWORD frame_id;
+
+            if (obj->ani.frames[i]) continue; /* already set */
+
+            frame_id = desc->frame_seq ? desc->frame_seq[i] : i;
+            if (frame_id >= obj->ani.num_frames)
+            {
+                frame_id = obj->ani.num_frames - 1;
+                ERR_(cursor)( "Sequence indicates frame past end of list, corrupt?\n" );
+            }
+            memset( &frame_desc, 0, sizeof(frame_desc) );
+            frame_desc.delay  = desc->frame_rates ? desc->frame_rates[i] : desc->delay;
+            frame_desc.frames = &desc->frames[frame_id];
+            if (!(obj->ani.frames[i] = alloc_cursoricon_handle( obj->is_icon )) ||
+                !NtUserSetCursorIconData( obj->ani.frames[i], NULL, NULL, &frame_desc ))
+            {
+                release_user_handle_ptr( obj );
+                return 0;
+            }
+
+            if (desc->frame_seq)
+            {
+                for (j = i + 1; j < obj->ani.num_steps; j++)
+                {
+                    if (desc->frame_seq[j] == frame_id) obj->ani.frames[j] = obj->ani.frames[i];
+                }
+            }
+        }
+    }
+
+    if (desc->flags & LR_SHARED)
+    {
+        obj->is_shared = TRUE;
+        if (obj->module.Length)
+        {
+            obj->rsrc = desc->rsrc;
+            list_add_head( &icon_cache, &obj->entry );
+        }
+    }
+
+    release_user_handle_ptr( obj );
+    return TRUE;
+}
+
 /***********************************************************************
  *          bmi_has_alpha
  */
@@ -1167,6 +1284,35 @@ done:
     return ret;
 }
 
+static HICON create_cursoricon_object( struct cursoricon_desc *desc, BOOL is_icon, HINSTANCE module,
+                                       const WCHAR *resname, HRSRC rsrc )
+{
+    WCHAR buf[MAX_PATH];
+    UNICODE_STRING module_name = { 0, sizeof(buf), buf };
+    UNICODE_STRING res_str = { 0 };
+    HICON handle;
+
+    if (!(handle = alloc_cursoricon_handle( is_icon ))) return 0;
+
+    if (module) LdrGetDllFullName( module, &module_name );
+
+    res_str.Buffer = (WCHAR *)resname;
+    if (!IS_INTRESOURCE(resname))
+    {
+        res_str.Length = lstrlenW( resname ) * sizeof(WCHAR);
+        res_str.MaximumLength = res_str.Length + sizeof(WCHAR);
+    }
+    desc->rsrc = rsrc; /* FIXME: we should probably avoid storing rsrc */
+
+    if (!NtUserSetCursorIconData( handle, &module_name, &res_str, desc ))
+    {
+        DestroyCursor( handle );
+        return 0;
+    }
+
+    return handle;
+}
+
 /***********************************************************************
  *          create_icon_from_bmi
  *
@@ -1177,53 +1323,17 @@ static HICON create_icon_from_bmi( const BITMAPINFO *bmi, DWORD maxsize, HMODULE
                                    UINT flags )
 {
     struct cursoricon_frame frame;
+    struct cursoricon_desc desc =
+    {
+        .flags = flags,
+        .frames = &frame,
+    };
     HICON ret;
 
     if (!create_icon_frame( bmi, maxsize, hotspot, bIcon, width, height, flags, &frame )) return 0;
 
-    ret = alloc_icon_handle( FALSE, 0 );
-    if (ret)
-    {
-        struct cursoricon_object *info = get_icon_ptr( ret );
-
-        info->is_icon = bIcon;
-        info->frame = frame;
-
-        if (!IS_INTRESOURCE(resname))
-        {
-            info->resname = HeapAlloc( GetProcessHeap(), 0, (lstrlenW(resname) + 1) * sizeof(WCHAR) );
-            if (info->resname) lstrcpyW( info->resname, resname );
-        }
-        else info->resname = MAKEINTRESOURCEW( LOWORD(resname) );
-
-        if (module)
-        {
-            WCHAR buf[MAX_PATH];
-            UNICODE_STRING module_name = { 0, sizeof(buf), buf };
-
-            if (!LdrGetDllFullName( module, &module_name ) &&
-                (info->module.Buffer = HeapAlloc( GetProcessHeap(), 0, module_name.Length )))
-            {
-                memcpy( info->module.Buffer, module_name.Buffer, module_name.Length );
-                info->module.Length = module_name.Length;
-            }
-        }
-
-        if (flags & LR_SHARED)
-        {
-            info->is_shared = TRUE;
-            if (module)
-            {
-                info->rsrc = rsrc;
-                list_add_head( &icon_cache, &info->entry );
-            }
-        }
-        release_user_handle_ptr( info );
-    }
-    else
-    {
-        free_icon_frame( &frame );
-    }
+    ret = create_cursoricon_object( &desc, bIcon, module, resname, rsrc );
+    if (!ret) free_icon_frame( &frame );
     return ret;
 }
 
diff --git a/include/ntuser.h b/include/ntuser.h
index c34270653ea..a54da6095f1 100644
--- a/include/ntuser.h
+++ b/include/ntuser.h
@@ -113,6 +113,19 @@ enum
 #define NTUSER_OBJ_ACCEL    0x08
 #define NTUSER_OBJ_HOOK     0x0f
 
+/* NtUserSetCursorIconData parameter, not compatible with Windows */
+struct cursoricon_desc
+{
+    UINT flags;
+    UINT num_steps;
+    UINT num_frames;
+    UINT delay;
+    struct cursoricon_frame *frames;
+    DWORD *frame_seq;
+    DWORD *frame_rates;
+    HRSRC rsrc;
+};
+
 /* internal messages codes */
 enum wine_internal_message
 {
@@ -199,6 +212,8 @@ HANDLE  WINAPI NtUserRemoveProp( HWND hwnd, const WCHAR *str );
 BOOL    WINAPI NtUserScrollDC( HDC hdc, INT dx, INT dy, const RECT *scroll, const RECT *clip,
                                HRGN ret_update_rgn, RECT *update_rect );
 HPALETTE WINAPI NtUserSelectPalette( HDC hdc, HPALETTE palette, WORD force_background );
+BOOL    WINAPI NtUserSetCursorIconData( HCURSOR cursor, UNICODE_STRING *module, UNICODE_STRING *res_name,
+                                        struct cursoricon_desc *desc );
 BOOL    WINAPI NtUserSetCursorPos( INT x, INT y );
 BOOL    WINAPI NtUserSetKeyboardState( BYTE *state );
 BOOL    WINAPI NtUserSetProcessDpiAwarenessContext( ULONG awareness, ULONG unknown );




More information about the wine-cvs mailing list