windows.media.speech: Add IIterable<IInspectable*> stubs.
[wine.git] / dlls / win32u / cursoricon.c
blob0249eb3da50e2a3f5c63c7850035c8decf6be2ee
1 /*
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
27 #if 0
28 #pragma makedep unix
29 #endif
31 #include <assert.h>
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) */
52 union
54 struct cursoricon_frame frame; /* frame-specific icon data */
55 struct
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 */
60 } ani;
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 );
72 obj = NULL;
74 return obj;
77 /***********************************************************************
78 * NtUserShowCursor (win32u.@)
80 INT WINAPI NtUserShowCursor( BOOL show )
82 HCURSOR cursor;
83 int increment = show ? 1 : -1;
84 int count;
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;
94 SERVER_END_REQ;
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 );
101 return count;
104 /***********************************************************************
105 * NtUserSetCursor (win32u.@)
107 HCURSOR WINAPI NtUserSetCursor( HCURSOR cursor )
109 struct cursoricon_object *obj;
110 HCURSOR old_cursor;
111 int show_count;
112 BOOL ret;
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;
126 SERVER_END_REQ;
127 if (!ret) return 0;
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 );
133 return old_cursor;
136 /***********************************************************************
137 * NtUserGetCursor (win32u.@)
139 HCURSOR WINAPI NtUserGetCursor(void)
141 HCURSOR ret;
143 SERVER_START_REQ( set_cursor )
145 req->flags = 0;
146 wine_server_call( req );
147 ret = wine_server_ptr_handle( reply->prev_handle );
149 SERVER_END_REQ;
150 return ret;
153 /***********************************************************************
154 * NtUserClipCursor (win32u.@)
156 BOOL WINAPI NtUserClipCursor( const RECT *rect )
158 UINT dpi;
159 BOOL ret;
160 RECT new_rect;
162 TRACE( "Clipping to %s\n", wine_dbgstr_rect(rect) );
164 if (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 ));
171 rect = &new_rect;
175 SERVER_START_REQ( set_cursor )
177 req->clip_msg = WM_WINE_CLIPCURSOR;
178 if (rect)
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;
196 SERVER_END_REQ;
197 if (ret) user_driver->pClipCursor( &new_rect );
198 return ret;
201 BOOL get_clip_cursor( RECT *rect )
203 UINT dpi;
204 BOOL ret;
206 if (!rect) return FALSE;
208 SERVER_START_REQ( set_cursor )
210 req->flags = 0;
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;
219 SERVER_END_REQ;
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 );
226 return ret;
229 HICON alloc_cursoricon_handle( BOOL is_icon )
231 struct cursoricon_object *obj;
232 HICON handle;
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 );
237 return handle;
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 );
249 return NULL;
251 ret = get_icon_ptr( obj->ani.frames[step] );
252 release_user_handle_ptr( obj );
253 return ret;
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 );
261 else if (obj)
263 ULONG param = obj->param;
264 void *ret_ptr;
265 ULONG ret_len;
266 UINT i;
268 assert( !obj->rsrc ); /* shared icons can't be freed */
270 if (!obj->is_ani)
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 );
276 else
278 for (i = 0; i < obj->ani.num_steps; i++)
280 HICON hFrame = obj->ani.frames[i];
282 if (hFrame)
284 UINT j;
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 );
296 free( obj );
297 if (param) KeUserModeCallback( NtUserCallFreeIcon, &param, sizeof(param), &ret_ptr, &ret_len );
298 user_driver->pDestroyCursorIcon( handle );
299 return TRUE;
301 return FALSE;
304 /***********************************************************************
305 * NtUserDestroyCursor (win32u.@)
307 BOOL WINAPI NtUserDestroyCursor( HCURSOR cursor, ULONG arg )
309 struct cursoricon_object *obj;
310 BOOL shared, ret;
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 );
319 return ret;
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;
329 UINT i, j;
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 SetLastError( ERROR_INVALID_CURSOR_HANDLE );
338 return FALSE;
341 obj->delay = desc->delay;
343 if (desc->num_steps)
345 if (!(obj->ani.frames = calloc( desc->num_steps, sizeof(*obj->ani.frames) )))
347 release_user_handle_ptr( obj );
348 return FALSE;
350 obj->is_ani = TRUE;
351 obj->ani.num_steps = desc->num_steps;
352 obj->ani.num_frames = desc->num_frames;
354 else obj->frame = desc->frames[0];
356 if (!res_name)
357 obj->resname = NULL;
358 else if (res_name->Length)
360 obj->resname = malloc( res_name->Length + sizeof(WCHAR) );
361 if (obj->resname)
363 memcpy( obj->resname, res_name->Buffer, res_name->Length );
364 obj->resname[res_name->Length / sizeof(WCHAR)] = 0;
367 else
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;
376 if (obj->is_ani)
378 /* Setup the animated frames in the correct sequence */
379 for (i = 0; i < desc->num_steps; i++)
381 struct cursoricon_desc frame_desc;
382 DWORD frame_id;
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 );
399 return 0;
402 if (desc->frame_seq)
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 );
423 return TRUE;
426 /***********************************************************************
427 * NtUserFindExistingCursorIcon (win32u.@)
429 HICON WINAPI NtUserFindExistingCursorIcon( UNICODE_STRING *module, UNICODE_STRING *res_name, void *desc )
431 struct cursoricon_object *ptr;
432 HICON ret = 0;
434 user_lock();
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;
442 break;
444 user_unlock();
445 return ret;
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 SetLastError( ERROR_INVALID_CURSOR_HANDLE );
458 return FALSE;
461 *width = obj->frame.width;
462 *height = obj->frame.height * 2;
463 release_user_handle_ptr( obj );
464 return TRUE;
467 /**********************************************************************
468 * NtUserGetCursorFrameInfo (win32u.@)
470 HCURSOR WINAPI NtUserGetCursorFrameInfo( HCURSOR cursor, DWORD istep, DWORD *rate_jiffies,
471 DWORD *num_steps )
473 struct cursoricon_object *obj;
474 HCURSOR ret = 0;
475 UINT icon_steps;
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, 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;
488 if (obj->is_ani)
489 icon_frames = obj->ani.num_frames;
490 if (obj->is_ani && icon_frames > 1)
491 ret = obj->ani.frames[istep];
492 else
493 ret = cursor;
494 if (icon_frames == 1)
496 *rate_jiffies = 0;
497 *num_steps = 1;
499 else if (icon_steps == 1)
501 *num_steps = ~0;
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)
511 *num_steps = ~0;
512 else
513 *num_steps = obj->ani.num_steps;
514 *rate_jiffies = frame->delay;
515 release_user_handle_ptr( frame );
519 release_user_handle_ptr( obj );
520 return ret;
523 /***********************************************************************
524 * copy_bitmap
526 * Helper function to duplicate a bitmap.
528 static HBITMAP copy_bitmap( HBITMAP bitmap )
530 HDC src, dst = 0;
531 HBITMAP new_bitmap = 0;
532 BITMAP bmp;
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 );
548 return new_bitmap;
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;
558 BOOL ret = TRUE;
560 if (!(obj = get_icon_ptr( icon )))
562 SetLastError( ERROR_INVALID_CURSOR_HANDLE );
563 return FALSE;
565 if (!(frame_obj = get_icon_frame_ptr( icon, 0 )))
567 release_user_handle_ptr( obj );
568 return FALSE;
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 );
582 ret = FALSE;
584 else if (obj->module.Length)
586 if (module)
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 */
592 if (res_name)
594 if (IS_INTRESOURCE( obj->resname ))
596 res_name->Buffer = obj->resname;
597 res_name->Length = 0;
599 else
601 size_t size = min( res_name->MaximumLength, lstrlenW( obj->resname) * sizeof(WCHAR) );
602 if (size) memcpy( res_name->Buffer, obj->resname, size );
603 module->Length = size / sizeof(WCHAR); /* length in chars, not bytes */
607 else
609 if (module) module->Length = 0;
610 if (res_name)
612 res_name->Length = 0;
613 res_name->Buffer = NULL;
616 release_user_handle_ptr( frame_obj );
617 release_user_handle_ptr( obj );
618 return ret;
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;
632 BOOL result = FALSE;
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);
640 return FALSE;
642 if (!(mem_dc = NtGdiCreateCompatibleDC( hdc )))
644 release_user_handle_ptr( obj );
645 return FALSE;
648 if (flags & DI_NOMIRROR)
649 FIXME_(icon)("Ignoring flag DI_NOMIRROR\n");
651 /* Calculate the size of the destination image. */
652 if (width == 0)
654 if (flags & DI_DEFAULTSIZE)
655 width = get_system_metrics( SM_CXICON );
656 else
657 width = obj->frame.width;
659 if (height == 0)
661 if (flags & DI_DEFAULTSIZE)
662 height = get_system_metrics( SM_CYICON );
663 else
664 height = obj->frame.height;
667 if (get_gdi_object_type( brush ) == NTGDI_OBJ_BRUSH)
669 HBRUSH prev_brush;
670 RECT r;
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 );
678 goto failed;
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 );
685 x = y = 0;
687 else
689 hdc_dest = hdc;
690 x = x0;
691 y = y0;
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)
704 BITMAP bm;
705 HBITMAP bmp = NtGdiGetDCObject( hdc_dest, NTGDI_OBJ_SURF );
706 alpha_blend = NtGdiExtGetObjectW( bmp, sizeof(bm), &bm ) && bm.bmBitsPixel > 8;
708 if (alpha_blend)
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;
718 if (flags & DI_MASK)
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 );
735 else
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 );
745 done:
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 );
752 result = TRUE;
753 if (hdc_dest != hdc) NtGdiDeleteObjectApp( hdc_dest );
754 if (offscreen_bitmap) NtGdiDeleteObjectApp( offscreen_bitmap );
755 failed:
756 NtGdiDeleteObjectApp( mem_dc );
757 release_user_handle_ptr( obj );
758 return result;
761 ULONG_PTR get_icon_param( HICON handle )
763 ULONG_PTR ret = 0;
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 );
767 else if (obj)
769 ret = obj->param;
770 release_user_handle_ptr( obj );
772 return ret;
775 ULONG_PTR set_icon_param( HICON handle, ULONG_PTR param )
777 ULONG_PTR ret = 0;
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 );
781 else if (obj)
783 ret = obj->param;
784 obj->param = param;
785 release_user_handle_ptr( obj );
787 return ret;