2 * Cursor and icon support
4 * Copyright 1995 Alexandre Julliard
5 * Copyright 1996 Martin Von Loewis
6 * Copyright 1997 Alex Korobka
7 * Copyright 1998 Turchanov Sergey
8 * Copyright 2007 Henri Verbeet
9 * Copyright 2009 Vincent Povirk for CodeWeavers
10 * Copyright 2016 Dmitry Timoshkov
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #include "ntgdi_private.h"
33 #include "ntuser_private.h"
34 #include "wine/server.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(cursor
);
38 WINE_DECLARE_DEBUG_CHANNEL(icon
);
40 struct cursoricon_object
42 struct user_object obj
; /* object header */
43 struct list entry
; /* entry in shared icons list */
44 ULONG_PTR param
; /* opaque param used by 16-bit code */
45 UNICODE_STRING module
; /* module for icons loaded from resources */
46 WCHAR
*resname
; /* resource name for icons loaded from resources */
47 HRSRC rsrc
; /* resource for shared icons */
48 BOOL is_shared
; /* whether this object is shared */
49 BOOL is_icon
; /* whether icon or cursor */
50 BOOL is_ani
; /* whether this object is a static cursor or an animated cursor */
51 UINT delay
; /* delay between this frame and the next (in jiffies) */
54 struct cursoricon_frame frame
; /* frame-specific icon data */
57 UINT num_frames
; /* number of frames in the icon/cursor */
58 UINT num_steps
; /* number of sequence steps in the icon/cursor */
59 HICON
*frames
; /* list of animated cursor frames */
64 static struct list icon_cache
= LIST_INIT( icon_cache
);
66 static struct cursoricon_object
*get_icon_ptr( HICON handle
)
68 struct cursoricon_object
*obj
= get_user_handle_ptr( handle
, NTUSER_OBJ_ICON
);
69 if (obj
== OBJ_OTHER_PROCESS
)
71 WARN( "icon handle %p from other process\n", handle
);
77 /***********************************************************************
78 * NtUserShowCursor (win32u.@)
80 INT WINAPI
NtUserShowCursor( BOOL show
)
83 int increment
= show
? 1 : -1;
86 SERVER_START_REQ( set_cursor
)
88 req
->flags
= SET_CURSOR_COUNT
;
89 req
->show_count
= increment
;
90 wine_server_call( req
);
91 cursor
= wine_server_ptr_handle( reply
->prev_handle
);
92 count
= reply
->prev_count
+ increment
;
96 TRACE("%d, count=%d\n", show
, count
);
98 if (show
&& !count
) user_driver
->pSetCursor( cursor
);
99 else if (!show
&& count
== -1) user_driver
->pSetCursor( 0 );
104 /***********************************************************************
105 * NtUserSetCursor (win32u.@)
107 HCURSOR WINAPI
NtUserSetCursor( HCURSOR cursor
)
109 struct cursoricon_object
*obj
;
114 TRACE( "%p\n", cursor
);
116 SERVER_START_REQ( set_cursor
)
118 req
->flags
= SET_CURSOR_HANDLE
;
119 req
->handle
= wine_server_user_handle( cursor
);
120 if ((ret
= !wine_server_call_err( req
)))
122 old_cursor
= wine_server_ptr_handle( reply
->prev_handle
);
123 show_count
= reply
->prev_count
;
129 user_driver
->pSetCursor( show_count
>= 0 ? cursor
: 0 );
131 if (!(obj
= get_icon_ptr( old_cursor
))) return 0;
132 release_user_handle_ptr( obj
);
136 /***********************************************************************
137 * NtUserGetCursor (win32u.@)
139 HCURSOR WINAPI
NtUserGetCursor(void)
143 SERVER_START_REQ( set_cursor
)
146 wine_server_call( req
);
147 ret
= wine_server_ptr_handle( reply
->prev_handle
);
153 /***********************************************************************
154 * NtUserClipCursor (win32u.@)
156 BOOL WINAPI
NtUserClipCursor( const RECT
*rect
)
162 TRACE( "Clipping to %s\n", wine_dbgstr_rect(rect
) );
166 if (rect
->left
> rect
->right
|| rect
->top
> rect
->bottom
) return FALSE
;
167 if ((dpi
= get_thread_dpi()))
169 HMONITOR monitor
= monitor_from_rect( rect
, MONITOR_DEFAULTTOPRIMARY
, dpi
);
170 new_rect
= map_dpi_rect( *rect
, dpi
, get_monitor_dpi( monitor
));
175 SERVER_START_REQ( set_cursor
)
177 req
->clip_msg
= WM_WINE_CLIPCURSOR
;
180 req
->flags
= SET_CURSOR_CLIP
;
181 req
->clip
.left
= rect
->left
;
182 req
->clip
.top
= rect
->top
;
183 req
->clip
.right
= rect
->right
;
184 req
->clip
.bottom
= rect
->bottom
;
186 else req
->flags
= SET_CURSOR_NOCLIP
;
188 if ((ret
= !wine_server_call( req
)))
190 new_rect
.left
= reply
->new_clip
.left
;
191 new_rect
.top
= reply
->new_clip
.top
;
192 new_rect
.right
= reply
->new_clip
.right
;
193 new_rect
.bottom
= reply
->new_clip
.bottom
;
197 if (ret
) user_driver
->pClipCursor( &new_rect
);
201 BOOL
get_clip_cursor( RECT
*rect
)
206 if (!rect
) return FALSE
;
208 SERVER_START_REQ( set_cursor
)
211 if ((ret
= !wine_server_call( req
)))
213 rect
->left
= reply
->new_clip
.left
;
214 rect
->top
= reply
->new_clip
.top
;
215 rect
->right
= reply
->new_clip
.right
;
216 rect
->bottom
= reply
->new_clip
.bottom
;
221 if (ret
&& (dpi
= get_thread_dpi()))
223 HMONITOR monitor
= monitor_from_rect( rect
, MONITOR_DEFAULTTOPRIMARY
, 0 );
224 *rect
= map_dpi_rect( *rect
, get_monitor_dpi( monitor
), dpi
);
229 HICON
alloc_cursoricon_handle( BOOL is_icon
)
231 struct cursoricon_object
*obj
;
234 if (!(obj
= calloc( 1, sizeof(*obj
) ))) return NULL
;
235 obj
->is_icon
= is_icon
;
236 if (!(handle
= alloc_user_handle( &obj
->obj
, NTUSER_OBJ_ICON
))) free( obj
);
240 static struct cursoricon_object
*get_icon_frame_ptr( HICON handle
, UINT step
)
242 struct cursoricon_object
*obj
, *ret
;
244 if (!(obj
= get_icon_ptr( handle
))) return NULL
;
245 if (!obj
->is_ani
) return obj
;
246 if (step
>= obj
->ani
.num_steps
)
248 release_user_handle_ptr( obj
);
251 ret
= get_icon_ptr( obj
->ani
.frames
[step
] );
252 release_user_handle_ptr( obj
);
256 static BOOL
free_icon_handle( HICON handle
)
258 struct cursoricon_object
*obj
= free_user_handle( handle
, NTUSER_OBJ_ICON
);
260 if (obj
== OBJ_OTHER_PROCESS
) WARN( "icon handle %p from other process\n", handle
);
263 ULONG param
= obj
->param
;
268 assert( !obj
->rsrc
); /* shared icons can't be freed */
272 if (obj
->frame
.alpha
) NtGdiDeleteObjectApp( obj
->frame
.alpha
);
273 if (obj
->frame
.color
) NtGdiDeleteObjectApp( obj
->frame
.color
);
274 if (obj
->frame
.mask
) NtGdiDeleteObjectApp( obj
->frame
.mask
);
278 for (i
= 0; i
< obj
->ani
.num_steps
; i
++)
280 HICON hFrame
= obj
->ani
.frames
[i
];
286 free_icon_handle( obj
->ani
.frames
[i
] );
287 for (j
= 0; j
< obj
->ani
.num_steps
; j
++)
289 if (obj
->ani
.frames
[j
] == hFrame
) obj
->ani
.frames
[j
] = 0;
293 free( obj
->ani
.frames
);
295 if (!IS_INTRESOURCE( obj
->resname
)) free( obj
->resname
);
297 if (param
) KeUserModeCallback( NtUserCallFreeIcon
, ¶m
, sizeof(param
), &ret_ptr
, &ret_len
);
298 user_driver
->pDestroyCursorIcon( handle
);
304 /***********************************************************************
305 * NtUserDestroyCursor (win32u.@)
307 BOOL WINAPI
NtUserDestroyCursor( HCURSOR cursor
, ULONG arg
)
309 struct cursoricon_object
*obj
;
312 TRACE( "%p\n", cursor
);
314 if (!(obj
= get_icon_ptr( cursor
))) return FALSE
;
315 shared
= obj
->is_shared
;
316 release_user_handle_ptr( obj
);
317 ret
= NtUserGetCursor() != cursor
;
318 if (!shared
) free_icon_handle( cursor
);
322 /***********************************************************************
323 * NtUserSetCursorIconData (win32u.@)
325 BOOL WINAPI
NtUserSetCursorIconData( HCURSOR cursor
, UNICODE_STRING
*module
, UNICODE_STRING
*res_name
,
326 struct cursoricon_desc
*desc
)
328 struct cursoricon_object
*obj
;
331 if (!(obj
= get_icon_ptr( cursor
))) return FALSE
;
333 if (obj
->is_ani
|| obj
->frame
.width
)
335 /* already initialized */
336 release_user_handle_ptr( obj
);
337 RtlSetLastWin32Error( ERROR_INVALID_CURSOR_HANDLE
);
341 obj
->delay
= desc
->delay
;
345 if (!(obj
->ani
.frames
= calloc( desc
->num_steps
, sizeof(*obj
->ani
.frames
) )))
347 release_user_handle_ptr( obj
);
351 obj
->ani
.num_steps
= desc
->num_steps
;
352 obj
->ani
.num_frames
= desc
->num_frames
;
354 else obj
->frame
= desc
->frames
[0];
358 else if (res_name
->Length
)
360 obj
->resname
= malloc( res_name
->Length
+ sizeof(WCHAR
) );
363 memcpy( obj
->resname
, res_name
->Buffer
, res_name
->Length
);
364 obj
->resname
[res_name
->Length
/ sizeof(WCHAR
)] = 0;
368 obj
->resname
= MAKEINTRESOURCEW( LOWORD(res_name
->Buffer
) );
370 if (module
&& module
->Length
&& (obj
->module
.Buffer
= malloc( module
->Length
)))
372 memcpy( obj
->module
.Buffer
, module
->Buffer
, module
->Length
);
373 obj
->module
.Length
= module
->Length
;
378 /* Setup the animated frames in the correct sequence */
379 for (i
= 0; i
< desc
->num_steps
; i
++)
381 struct cursoricon_desc frame_desc
;
384 if (obj
->ani
.frames
[i
]) continue; /* already set */
386 frame_id
= desc
->frame_seq
? desc
->frame_seq
[i
] : i
;
387 if (frame_id
>= obj
->ani
.num_frames
)
389 frame_id
= obj
->ani
.num_frames
- 1;
390 ERR_(cursor
)( "Sequence indicates frame past end of list, corrupt?\n" );
392 memset( &frame_desc
, 0, sizeof(frame_desc
) );
393 frame_desc
.delay
= desc
->frame_rates
? desc
->frame_rates
[i
] : desc
->delay
;
394 frame_desc
.frames
= &desc
->frames
[frame_id
];
395 if (!(obj
->ani
.frames
[i
] = alloc_cursoricon_handle( obj
->is_icon
)) ||
396 !NtUserSetCursorIconData( obj
->ani
.frames
[i
], NULL
, NULL
, &frame_desc
))
398 release_user_handle_ptr( obj
);
404 for (j
= i
+ 1; j
< obj
->ani
.num_steps
; j
++)
406 if (desc
->frame_seq
[j
] == frame_id
) obj
->ani
.frames
[j
] = obj
->ani
.frames
[i
];
412 if (desc
->flags
& LR_SHARED
)
414 obj
->is_shared
= TRUE
;
415 if (obj
->module
.Length
)
417 obj
->rsrc
= desc
->rsrc
;
418 list_add_head( &icon_cache
, &obj
->entry
);
422 release_user_handle_ptr( obj
);
426 /***********************************************************************
427 * NtUserFindExistingCursorIcon (win32u.@)
429 HICON WINAPI
NtUserFindExistingCursorIcon( UNICODE_STRING
*module
, UNICODE_STRING
*res_name
, void *desc
)
431 struct cursoricon_object
*ptr
;
435 LIST_FOR_EACH_ENTRY( ptr
, &icon_cache
, struct cursoricon_object
, entry
)
437 if (ptr
->module
.Length
!= module
->Length
) continue;
438 if (memcmp( ptr
->module
.Buffer
, module
->Buffer
, module
->Length
)) continue;
439 /* We pass rsrc as desc argument, this is not compatible with Windows */
440 if (ptr
->rsrc
!= desc
) continue;
441 ret
= ptr
->obj
.handle
;
448 /***********************************************************************
449 * NtUserGetIconSize (win32u.@)
451 BOOL WINAPI
NtUserGetIconSize( HICON handle
, UINT step
, LONG
*width
, LONG
*height
)
453 struct cursoricon_object
*obj
;
455 if (!(obj
= get_icon_frame_ptr( handle
, step
)))
457 RtlSetLastWin32Error( ERROR_INVALID_CURSOR_HANDLE
);
461 *width
= obj
->frame
.width
;
462 *height
= obj
->frame
.height
* 2;
463 release_user_handle_ptr( obj
);
467 /**********************************************************************
468 * NtUserGetCursorFrameInfo (win32u.@)
470 HCURSOR WINAPI
NtUserGetCursorFrameInfo( HCURSOR cursor
, DWORD istep
, DWORD
*rate_jiffies
,
473 struct cursoricon_object
*obj
;
477 if (!rate_jiffies
|| !num_steps
) return 0;
479 if (!(obj
= get_icon_ptr( cursor
))) return 0;
481 TRACE( "%p => %d %p %p\n", cursor
, (int)istep
, rate_jiffies
, num_steps
);
483 icon_steps
= obj
->is_ani
? obj
->ani
.num_steps
: 1;
484 if (istep
< icon_steps
|| !obj
->is_ani
)
486 UINT icon_frames
= 1;
489 icon_frames
= obj
->ani
.num_frames
;
490 if (obj
->is_ani
&& icon_frames
> 1)
491 ret
= obj
->ani
.frames
[istep
];
494 if (icon_frames
== 1)
499 else if (icon_steps
== 1)
502 *rate_jiffies
= obj
->delay
;
504 else if (istep
< icon_steps
)
506 struct cursoricon_object
*frame
;
508 *num_steps
= icon_steps
;
509 frame
= get_icon_ptr( obj
->ani
.frames
[istep
] );
510 if (obj
->ani
.num_steps
== 1)
513 *num_steps
= obj
->ani
.num_steps
;
514 *rate_jiffies
= frame
->delay
;
515 release_user_handle_ptr( frame
);
519 release_user_handle_ptr( obj
);
523 /***********************************************************************
526 * Helper function to duplicate a bitmap.
528 static HBITMAP
copy_bitmap( HBITMAP bitmap
)
531 HBITMAP new_bitmap
= 0;
534 if (!bitmap
) return 0;
535 if (!NtGdiExtGetObjectW( bitmap
, sizeof(bmp
), &bmp
)) return 0;
537 if ((src
= NtGdiCreateCompatibleDC( 0 )) && (dst
= NtGdiCreateCompatibleDC( 0 )))
539 NtGdiSelectBitmap( src
, bitmap
);
540 if ((new_bitmap
= NtGdiCreateCompatibleBitmap( src
, bmp
.bmWidth
, bmp
.bmHeight
)))
542 NtGdiSelectBitmap( dst
, new_bitmap
);
543 NtGdiBitBlt( dst
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, src
, 0, 0, SRCCOPY
, 0, 0 );
546 NtGdiDeleteObjectApp( dst
);
547 NtGdiDeleteObjectApp( src
);
551 /**********************************************************************
552 * NtUserGetIconInfo (win32u.@)
554 BOOL WINAPI
NtUserGetIconInfo( HICON icon
, ICONINFO
*info
, UNICODE_STRING
*module
,
555 UNICODE_STRING
*res_name
, DWORD
*bpp
, LONG unk
)
557 struct cursoricon_object
*obj
, *frame_obj
;
560 if (!(obj
= get_icon_ptr( icon
)))
562 RtlSetLastWin32Error( ERROR_INVALID_CURSOR_HANDLE
);
565 if (!(frame_obj
= get_icon_frame_ptr( icon
, 0 )))
567 release_user_handle_ptr( obj
);
571 TRACE( "%p => %dx%d\n", icon
, frame_obj
->frame
.width
, frame_obj
->frame
.height
);
573 info
->fIcon
= obj
->is_icon
;
574 info
->xHotspot
= frame_obj
->frame
.hotspot
.x
;
575 info
->yHotspot
= frame_obj
->frame
.hotspot
.y
;
576 info
->hbmColor
= copy_bitmap( frame_obj
->frame
.color
);
577 info
->hbmMask
= copy_bitmap( frame_obj
->frame
.mask
);
578 if (!info
->hbmMask
|| (!info
->hbmColor
&& frame_obj
->frame
.color
))
580 NtGdiDeleteObjectApp( info
->hbmMask
);
581 NtGdiDeleteObjectApp( info
->hbmColor
);
584 else if (obj
->module
.Length
)
588 size_t size
= min( module
->MaximumLength
, obj
->module
.Length
);
589 if (size
) memcpy( module
->Buffer
, obj
->module
.Buffer
, size
);
590 module
->Length
= size
/ sizeof(WCHAR
); /* length in chars, not bytes */
594 if (IS_INTRESOURCE( obj
->resname
))
596 res_name
->Buffer
= obj
->resname
;
597 res_name
->Length
= 0;
601 size_t size
= min( res_name
->MaximumLength
, lstrlenW( obj
->resname
) * sizeof(WCHAR
) );
602 if (size
) memcpy( res_name
->Buffer
, obj
->resname
, size
);
603 res_name
->Length
= size
/ sizeof(WCHAR
); /* length in chars, not bytes */
609 if (module
) module
->Length
= 0;
612 res_name
->Length
= 0;
613 res_name
->Buffer
= NULL
;
616 release_user_handle_ptr( frame_obj
);
617 release_user_handle_ptr( obj
);
621 /******************************************************************************
622 * NtUserDrawIconEx (win32u.@)
624 BOOL WINAPI
NtUserDrawIconEx( HDC hdc
, INT x0
, INT y0
, HICON icon
, INT width
,
625 INT height
, UINT step
, HBRUSH brush
, UINT flags
)
627 struct cursoricon_object
*obj
;
628 HBITMAP offscreen_bitmap
= 0;
629 HDC hdc_dest
, mem_dc
;
630 COLORREF old_fg
, old_bg
;
631 INT x
, y
, nStretchMode
;
634 TRACE_(icon
)( "(hdc=%p,pos=%d.%d,hicon=%p,extend=%d.%d,step=%d,br=%p,flags=0x%08x)\n",
635 hdc
, x0
, y0
, icon
, width
, height
, step
, brush
, flags
);
637 if (!(obj
= get_icon_frame_ptr( icon
, step
)))
639 FIXME_(icon
)("Error retrieving icon frame %d\n", step
);
642 if (!(mem_dc
= NtGdiCreateCompatibleDC( hdc
)))
644 release_user_handle_ptr( obj
);
648 if (flags
& DI_NOMIRROR
)
649 FIXME_(icon
)("Ignoring flag DI_NOMIRROR\n");
651 /* Calculate the size of the destination image. */
654 if (flags
& DI_DEFAULTSIZE
)
655 width
= get_system_metrics( SM_CXICON
);
657 width
= obj
->frame
.width
;
661 if (flags
& DI_DEFAULTSIZE
)
662 height
= get_system_metrics( SM_CYICON
);
664 height
= obj
->frame
.height
;
667 if (get_gdi_object_type( brush
) == NTGDI_OBJ_BRUSH
)
672 SetRect(&r
, 0, 0, width
, width
);
674 if (!(hdc_dest
= NtGdiCreateCompatibleDC(hdc
))) goto failed
;
675 if (!(offscreen_bitmap
= NtGdiCreateCompatibleBitmap(hdc
, width
, height
)))
677 NtGdiDeleteObjectApp( hdc_dest
);
680 NtGdiSelectBitmap( hdc_dest
, offscreen_bitmap
);
682 prev_brush
= NtGdiSelectBrush( hdc_dest
, brush
);
683 NtGdiPatBlt( hdc_dest
, r
.left
, r
.top
, r
.right
- r
.left
, r
.bottom
- r
.top
, PATCOPY
);
684 if (prev_brush
) NtGdiSelectBrush( hdc_dest
, prev_brush
);
694 nStretchMode
= set_stretch_blt_mode( hdc
, STRETCH_DELETESCANS
);
695 NtGdiGetAndSetDCDword( hdc
, NtGdiSetTextColor
, RGB(0,0,0), &old_fg
);
696 NtGdiGetAndSetDCDword( hdc
, NtGdiSetBkColor
, RGB(255,255,255), &old_bg
);
698 if (obj
->frame
.alpha
&& (flags
& DI_IMAGE
))
700 BOOL alpha_blend
= TRUE
;
702 if (get_gdi_object_type( hdc_dest
) == NTGDI_OBJ_MEMDC
)
705 HBITMAP bmp
= NtGdiGetDCObject( hdc_dest
, NTGDI_OBJ_SURF
);
706 alpha_blend
= NtGdiExtGetObjectW( bmp
, sizeof(bm
), &bm
) && bm
.bmBitsPixel
> 8;
710 BLENDFUNCTION pixelblend
= { AC_SRC_OVER
, 0, 255, AC_SRC_ALPHA
};
711 NtGdiSelectBitmap( mem_dc
, obj
->frame
.alpha
);
712 if (NtGdiAlphaBlend( hdc_dest
, x
, y
, width
, height
, mem_dc
,
713 0, 0, obj
->frame
.width
, obj
->frame
.height
,
714 pixelblend
, 0 )) goto done
;
720 DWORD rop
= (flags
& DI_IMAGE
) ? SRCAND
: SRCCOPY
;
721 NtGdiSelectBitmap( mem_dc
, obj
->frame
.mask
);
722 NtGdiStretchBlt( hdc_dest
, x
, y
, width
, height
,
723 mem_dc
, 0, 0, obj
->frame
.width
, obj
->frame
.height
, rop
, 0 );
726 if (flags
& DI_IMAGE
)
728 if (obj
->frame
.color
)
730 DWORD rop
= (flags
& DI_MASK
) ? SRCINVERT
: SRCCOPY
;
731 NtGdiSelectBitmap( mem_dc
, obj
->frame
.color
);
732 NtGdiStretchBlt( hdc_dest
, x
, y
, width
, height
,
733 mem_dc
, 0, 0, obj
->frame
.width
, obj
->frame
.height
, rop
, 0 );
737 DWORD rop
= (flags
& DI_MASK
) ? SRCINVERT
: SRCCOPY
;
738 NtGdiSelectBitmap( mem_dc
, obj
->frame
.mask
);
739 NtGdiStretchBlt( hdc_dest
, x
, y
, width
, height
,
740 mem_dc
, 0, obj
->frame
.height
, obj
->frame
.width
,
741 obj
->frame
.height
, rop
, 0 );
746 if (offscreen_bitmap
) NtGdiBitBlt( hdc
, x0
, y0
, width
, height
, hdc_dest
, 0, 0, SRCCOPY
, 0, 0 );
748 NtGdiGetAndSetDCDword( hdc
, NtGdiSetTextColor
, old_fg
, NULL
);
749 NtGdiGetAndSetDCDword( hdc
, NtGdiSetBkColor
, old_bg
, NULL
);
750 nStretchMode
= set_stretch_blt_mode( hdc
, nStretchMode
);
753 if (hdc_dest
!= hdc
) NtGdiDeleteObjectApp( hdc_dest
);
754 if (offscreen_bitmap
) NtGdiDeleteObjectApp( offscreen_bitmap
);
756 NtGdiDeleteObjectApp( mem_dc
);
757 release_user_handle_ptr( obj
);
761 ULONG_PTR
get_icon_param( HICON handle
)
764 struct cursoricon_object
*obj
= get_user_handle_ptr( handle
, NTUSER_OBJ_ICON
);
766 if (obj
== OBJ_OTHER_PROCESS
) WARN( "icon handle %p from other process\n", handle
);
770 release_user_handle_ptr( obj
);
775 ULONG_PTR
set_icon_param( HICON handle
, ULONG_PTR param
)
778 struct cursoricon_object
*obj
= get_user_handle_ptr( handle
, NTUSER_OBJ_ICON
);
780 if (obj
== OBJ_OTHER_PROCESS
) WARN( "icon handle %p from other process\n", handle
);
785 release_user_handle_ptr( obj
);
790 /******************************************************************************
791 * CopyImage (win32u.so)
793 HANDLE WINAPI
CopyImage( HANDLE hwnd
, UINT type
, INT dx
, INT dy
, UINT flags
)
798 struct copy_image_params params
=
799 { .hwnd
= hwnd
, .type
= type
, .dx
= dx
, .dy
= dy
, .flags
= flags
};
801 ret
= KeUserModeCallback( NtUserCopyImage
, ¶ms
, sizeof(params
), &ret_ptr
, &ret_len
);
802 return UlongToHandle( ret
);
805 /******************************************************************************
806 * LoadImage (win32u.so)
808 HANDLE WINAPI
LoadImageW( HINSTANCE hinst
, const WCHAR
*name
, UINT type
,
809 INT dx
, INT dy
, UINT flags
)
814 struct load_image_params params
=
815 { .hinst
= hinst
, .name
= name
, .type
= type
, .dx
= dx
, .dy
= dy
, .flags
= flags
};
819 ERR( "name %s not supported in Unix modules\n", debugstr_w( name
));
822 ret
= KeUserModeCallback( NtUserLoadImage
, ¶ms
, sizeof(params
), &ret_ptr
, &ret_len
);
823 return UlongToHandle( ret
);