mapi32: Remove DECLSPEC_HIDDEN usage.
[wine.git] / dlls / win32u / cursoricon.c
blob51226ed81a580caedcc863478eb3f349a1f4ec8a
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 BOOL process_wine_setcursor( HWND hwnd, HWND window, HCURSOR handle )
79 TRACE( "hwnd %p, window %p, hcursor %p\n", hwnd, window, handle );
80 user_driver->pSetCursor( window, handle );
81 return TRUE;
84 /***********************************************************************
85 * NtUserShowCursor (win32u.@)
87 INT WINAPI NtUserShowCursor( BOOL show )
89 int increment = show ? 1 : -1;
90 int count;
92 SERVER_START_REQ( set_cursor )
94 req->flags = SET_CURSOR_COUNT;
95 req->show_count = increment;
96 wine_server_call( req );
97 count = reply->prev_count + increment;
99 SERVER_END_REQ;
101 TRACE("%d, count=%d\n", show, count );
102 return count;
105 /***********************************************************************
106 * NtUserSetCursor (win32u.@)
108 HCURSOR WINAPI NtUserSetCursor( HCURSOR cursor )
110 struct cursoricon_object *obj;
111 HCURSOR old_cursor;
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 )))
121 old_cursor = wine_server_ptr_handle( reply->prev_handle );
123 SERVER_END_REQ;
124 if (!ret) return 0;
126 if (!(obj = get_icon_ptr( old_cursor ))) return 0;
127 release_user_handle_ptr( obj );
128 return old_cursor;
131 /***********************************************************************
132 * NtUserGetCursor (win32u.@)
134 HCURSOR WINAPI NtUserGetCursor(void)
136 HCURSOR ret;
138 SERVER_START_REQ( set_cursor )
140 req->flags = 0;
141 wine_server_call( req );
142 ret = wine_server_ptr_handle( reply->prev_handle );
144 SERVER_END_REQ;
145 return ret;
148 HICON alloc_cursoricon_handle( BOOL is_icon )
150 struct cursoricon_object *obj;
151 HICON handle;
153 if (!(obj = calloc( 1, sizeof(*obj) ))) return NULL;
154 obj->is_icon = is_icon;
155 if (!(handle = alloc_user_handle( &obj->obj, NTUSER_OBJ_ICON ))) free( obj );
156 return handle;
159 static struct cursoricon_object *get_icon_frame_ptr( HICON handle, UINT step )
161 struct cursoricon_object *obj, *ret;
163 if (!(obj = get_icon_ptr( handle ))) return NULL;
164 if (!obj->is_ani) return obj;
165 if (step >= obj->ani.num_steps)
167 release_user_handle_ptr( obj );
168 return NULL;
170 ret = get_icon_ptr( obj->ani.frames[step] );
171 release_user_handle_ptr( obj );
172 return ret;
175 static BOOL free_icon_handle( HICON handle )
177 struct cursoricon_object *obj = free_user_handle( handle, NTUSER_OBJ_ICON );
179 if (obj == OBJ_OTHER_PROCESS) WARN( "icon handle %p from other process\n", handle );
180 else if (obj)
182 ULONG param = obj->param;
183 void *ret_ptr;
184 ULONG ret_len;
185 UINT i;
187 assert( !obj->rsrc ); /* shared icons can't be freed */
189 if (!obj->is_ani)
191 if (obj->frame.alpha) NtGdiDeleteObjectApp( obj->frame.alpha );
192 if (obj->frame.color) NtGdiDeleteObjectApp( obj->frame.color );
193 if (obj->frame.mask) NtGdiDeleteObjectApp( obj->frame.mask );
195 else
197 for (i = 0; i < obj->ani.num_steps; i++)
199 HICON hFrame = obj->ani.frames[i];
201 if (hFrame)
203 UINT j;
205 free_icon_handle( obj->ani.frames[i] );
206 for (j = 0; j < obj->ani.num_steps; j++)
208 if (obj->ani.frames[j] == hFrame) obj->ani.frames[j] = 0;
212 free( obj->ani.frames );
214 if (!IS_INTRESOURCE( obj->resname )) free( obj->resname );
215 free( obj );
216 if (param) KeUserModeCallback( NtUserCallFreeIcon, &param, sizeof(param), &ret_ptr, &ret_len );
217 user_driver->pDestroyCursorIcon( handle );
218 return TRUE;
220 return FALSE;
223 /***********************************************************************
224 * NtUserDestroyCursor (win32u.@)
226 BOOL WINAPI NtUserDestroyCursor( HCURSOR cursor, ULONG arg )
228 struct cursoricon_object *obj;
229 BOOL shared, ret;
231 TRACE( "%p\n", cursor );
233 if (!(obj = get_icon_ptr( cursor ))) return FALSE;
234 shared = obj->is_shared;
235 release_user_handle_ptr( obj );
236 ret = NtUserGetCursor() != cursor;
237 if (!shared) free_icon_handle( cursor );
238 return ret;
241 /***********************************************************************
242 * NtUserSetCursorIconData (win32u.@)
244 BOOL WINAPI NtUserSetCursorIconData( HCURSOR cursor, UNICODE_STRING *module, UNICODE_STRING *res_name,
245 struct cursoricon_desc *desc )
247 struct cursoricon_object *obj;
248 UINT i, j;
250 if (!(obj = get_icon_ptr( cursor ))) return FALSE;
252 if (obj->is_ani || obj->frame.width)
254 /* already initialized */
255 release_user_handle_ptr( obj );
256 RtlSetLastWin32Error( ERROR_INVALID_CURSOR_HANDLE );
257 return FALSE;
260 obj->delay = desc->delay;
262 if (desc->num_steps)
264 if (!(obj->ani.frames = calloc( desc->num_steps, sizeof(*obj->ani.frames) )))
266 release_user_handle_ptr( obj );
267 return FALSE;
269 obj->is_ani = TRUE;
270 obj->ani.num_steps = desc->num_steps;
271 obj->ani.num_frames = desc->num_frames;
273 else obj->frame = desc->frames[0];
275 if (!res_name)
276 obj->resname = NULL;
277 else if (res_name->Length)
279 obj->resname = malloc( res_name->Length + sizeof(WCHAR) );
280 if (obj->resname)
282 memcpy( obj->resname, res_name->Buffer, res_name->Length );
283 obj->resname[res_name->Length / sizeof(WCHAR)] = 0;
286 else
287 obj->resname = MAKEINTRESOURCEW( LOWORD(res_name->Buffer) );
289 if (module && module->Length && (obj->module.Buffer = malloc( module->Length )))
291 memcpy( obj->module.Buffer, module->Buffer, module->Length );
292 obj->module.Length = module->Length;
295 if (obj->is_ani)
297 /* Setup the animated frames in the correct sequence */
298 for (i = 0; i < desc->num_steps; i++)
300 struct cursoricon_desc frame_desc;
301 DWORD frame_id;
303 if (obj->ani.frames[i]) continue; /* already set */
305 frame_id = desc->frame_seq ? desc->frame_seq[i] : i;
306 if (frame_id >= obj->ani.num_frames)
308 frame_id = obj->ani.num_frames - 1;
309 ERR_(cursor)( "Sequence indicates frame past end of list, corrupt?\n" );
311 memset( &frame_desc, 0, sizeof(frame_desc) );
312 frame_desc.delay = desc->frame_rates ? desc->frame_rates[i] : desc->delay;
313 frame_desc.frames = &desc->frames[frame_id];
314 if (!(obj->ani.frames[i] = alloc_cursoricon_handle( obj->is_icon )) ||
315 !NtUserSetCursorIconData( obj->ani.frames[i], NULL, NULL, &frame_desc ))
317 release_user_handle_ptr( obj );
318 return 0;
321 if (desc->frame_seq)
323 for (j = i + 1; j < obj->ani.num_steps; j++)
325 if (desc->frame_seq[j] == frame_id) obj->ani.frames[j] = obj->ani.frames[i];
331 if (desc->flags & LR_SHARED)
333 obj->is_shared = TRUE;
334 if (obj->module.Length)
336 obj->rsrc = desc->rsrc;
337 list_add_head( &icon_cache, &obj->entry );
341 release_user_handle_ptr( obj );
342 return TRUE;
345 /***********************************************************************
346 * NtUserFindExistingCursorIcon (win32u.@)
348 HICON WINAPI NtUserFindExistingCursorIcon( UNICODE_STRING *module, UNICODE_STRING *res_name, void *desc )
350 struct cursoricon_object *ptr;
351 HICON ret = 0;
353 user_lock();
354 LIST_FOR_EACH_ENTRY( ptr, &icon_cache, struct cursoricon_object, entry )
356 if (ptr->module.Length != module->Length) continue;
357 if (memcmp( ptr->module.Buffer, module->Buffer, module->Length )) continue;
358 /* We pass rsrc as desc argument, this is not compatible with Windows */
359 if (ptr->rsrc != desc) continue;
360 ret = ptr->obj.handle;
361 break;
363 user_unlock();
364 return ret;
367 /***********************************************************************
368 * NtUserGetIconSize (win32u.@)
370 BOOL WINAPI NtUserGetIconSize( HICON handle, UINT step, LONG *width, LONG *height )
372 struct cursoricon_object *obj;
374 if (!(obj = get_icon_frame_ptr( handle, step )))
376 RtlSetLastWin32Error( ERROR_INVALID_CURSOR_HANDLE );
377 return FALSE;
380 *width = obj->frame.width;
381 *height = obj->frame.height * 2;
382 release_user_handle_ptr( obj );
383 return TRUE;
386 /**********************************************************************
387 * NtUserGetCursorFrameInfo (win32u.@)
389 HCURSOR WINAPI NtUserGetCursorFrameInfo( HCURSOR cursor, DWORD istep, DWORD *rate_jiffies,
390 DWORD *num_steps )
392 struct cursoricon_object *obj;
393 HCURSOR ret = 0;
394 UINT icon_steps;
396 if (!rate_jiffies || !num_steps) return 0;
398 if (!(obj = get_icon_ptr( cursor ))) return 0;
400 TRACE( "%p => %d %p %p\n", cursor, (int)istep, rate_jiffies, num_steps );
402 icon_steps = obj->is_ani ? obj->ani.num_steps : 1;
403 if (istep < icon_steps || !obj->is_ani)
405 UINT icon_frames = 1;
407 if (obj->is_ani)
408 icon_frames = obj->ani.num_frames;
409 if (obj->is_ani && icon_frames > 1)
410 ret = obj->ani.frames[istep];
411 else
412 ret = cursor;
413 if (icon_frames == 1)
415 *rate_jiffies = 0;
416 *num_steps = 1;
418 else if (icon_steps == 1)
420 *num_steps = ~0;
421 *rate_jiffies = obj->delay;
423 else if (istep < icon_steps)
425 struct cursoricon_object *frame;
427 *num_steps = icon_steps;
428 frame = get_icon_ptr( obj->ani.frames[istep] );
429 if (obj->ani.num_steps == 1)
430 *num_steps = ~0;
431 else
432 *num_steps = obj->ani.num_steps;
433 *rate_jiffies = frame->delay;
434 release_user_handle_ptr( frame );
438 release_user_handle_ptr( obj );
439 return ret;
442 /***********************************************************************
443 * copy_bitmap
445 * Helper function to duplicate a bitmap.
447 static HBITMAP copy_bitmap( HBITMAP bitmap )
449 HDC src, dst = 0;
450 HBITMAP new_bitmap = 0;
451 BITMAP bmp;
453 if (!bitmap) return 0;
454 if (!NtGdiExtGetObjectW( bitmap, sizeof(bmp), &bmp )) return 0;
456 if ((src = NtGdiCreateCompatibleDC( 0 )) && (dst = NtGdiCreateCompatibleDC( 0 )))
458 NtGdiSelectBitmap( src, bitmap );
459 if ((new_bitmap = NtGdiCreateCompatibleBitmap( src, bmp.bmWidth, bmp.bmHeight )))
461 NtGdiSelectBitmap( dst, new_bitmap );
462 NtGdiBitBlt( dst, 0, 0, bmp.bmWidth, bmp.bmHeight, src, 0, 0, SRCCOPY, 0, 0 );
465 NtGdiDeleteObjectApp( dst );
466 NtGdiDeleteObjectApp( src );
467 return new_bitmap;
470 /**********************************************************************
471 * NtUserGetIconInfo (win32u.@)
473 BOOL WINAPI NtUserGetIconInfo( HICON icon, ICONINFO *info, UNICODE_STRING *module,
474 UNICODE_STRING *res_name, DWORD *bpp, LONG unk )
476 struct cursoricon_object *obj, *frame_obj;
477 BOOL ret = TRUE;
479 if (!(obj = get_icon_ptr( icon )))
481 RtlSetLastWin32Error( ERROR_INVALID_CURSOR_HANDLE );
482 return FALSE;
484 if (!(frame_obj = get_icon_frame_ptr( icon, 0 )))
486 release_user_handle_ptr( obj );
487 return FALSE;
490 TRACE( "%p => %dx%d\n", icon, frame_obj->frame.width, frame_obj->frame.height );
492 info->fIcon = obj->is_icon;
493 info->xHotspot = frame_obj->frame.hotspot.x;
494 info->yHotspot = frame_obj->frame.hotspot.y;
495 info->hbmColor = copy_bitmap( frame_obj->frame.color );
496 info->hbmMask = copy_bitmap( frame_obj->frame.mask );
497 if (!info->hbmMask || (!info->hbmColor && frame_obj->frame.color))
499 NtGdiDeleteObjectApp( info->hbmMask );
500 NtGdiDeleteObjectApp( info->hbmColor );
501 ret = FALSE;
503 else if (obj->module.Length)
505 if (module)
507 size_t size = min( module->MaximumLength, obj->module.Length );
508 if (size) memcpy( module->Buffer, obj->module.Buffer, size );
509 module->Length = size / sizeof(WCHAR); /* length in chars, not bytes */
511 if (res_name)
513 if (IS_INTRESOURCE( obj->resname ))
515 res_name->Buffer = obj->resname;
516 res_name->Length = 0;
518 else
520 size_t size = min( res_name->MaximumLength, lstrlenW( obj->resname) * sizeof(WCHAR) );
521 if (size) memcpy( res_name->Buffer, obj->resname, size );
522 res_name->Length = size / sizeof(WCHAR); /* length in chars, not bytes */
526 else
528 if (module) module->Length = 0;
529 if (res_name)
531 res_name->Length = 0;
532 res_name->Buffer = NULL;
535 release_user_handle_ptr( frame_obj );
536 release_user_handle_ptr( obj );
537 return ret;
540 /******************************************************************************
541 * NtUserDrawIconEx (win32u.@)
543 BOOL WINAPI NtUserDrawIconEx( HDC hdc, INT x0, INT y0, HICON icon, INT width,
544 INT height, UINT step, HBRUSH brush, UINT flags )
546 struct cursoricon_object *obj;
547 HBITMAP offscreen_bitmap = 0;
548 HDC hdc_dest, mem_dc;
549 COLORREF old_fg, old_bg;
550 INT x, y, nStretchMode;
551 BOOL result = FALSE;
553 TRACE_(icon)( "(hdc=%p,pos=%d.%d,hicon=%p,extend=%d.%d,step=%d,br=%p,flags=0x%08x)\n",
554 hdc, x0, y0, icon, width, height, step, brush, flags );
556 if (!(obj = get_icon_frame_ptr( icon, step )))
558 FIXME_(icon)("Error retrieving icon frame %d\n", step);
559 return FALSE;
561 if (!(mem_dc = NtGdiCreateCompatibleDC( hdc )))
563 release_user_handle_ptr( obj );
564 return FALSE;
567 if (flags & DI_NOMIRROR)
568 FIXME_(icon)("Ignoring flag DI_NOMIRROR\n");
570 /* Calculate the size of the destination image. */
571 if (width == 0)
573 if (flags & DI_DEFAULTSIZE)
574 width = get_system_metrics( SM_CXICON );
575 else
576 width = obj->frame.width;
578 if (height == 0)
580 if (flags & DI_DEFAULTSIZE)
581 height = get_system_metrics( SM_CYICON );
582 else
583 height = obj->frame.height;
586 if (get_gdi_object_type( brush ) == NTGDI_OBJ_BRUSH)
588 HBRUSH prev_brush;
589 RECT r;
591 SetRect(&r, 0, 0, width, width);
593 if (!(hdc_dest = NtGdiCreateCompatibleDC(hdc))) goto failed;
594 if (!(offscreen_bitmap = NtGdiCreateCompatibleBitmap(hdc, width, height)))
596 NtGdiDeleteObjectApp( hdc_dest );
597 goto failed;
599 NtGdiSelectBitmap( hdc_dest, offscreen_bitmap );
601 prev_brush = NtGdiSelectBrush( hdc_dest, brush );
602 NtGdiPatBlt( hdc_dest, r.left, r.top, r.right - r.left, r.bottom - r.top, PATCOPY );
603 if (prev_brush) NtGdiSelectBrush( hdc_dest, prev_brush );
604 x = y = 0;
606 else
608 hdc_dest = hdc;
609 x = x0;
610 y = y0;
613 nStretchMode = set_stretch_blt_mode( hdc, STRETCH_DELETESCANS );
614 NtGdiGetAndSetDCDword( hdc, NtGdiSetTextColor, RGB(0,0,0), &old_fg );
615 NtGdiGetAndSetDCDword( hdc, NtGdiSetBkColor, RGB(255,255,255), &old_bg );
617 if (obj->frame.alpha && (flags & DI_IMAGE))
619 BOOL alpha_blend = TRUE;
621 if (get_gdi_object_type( hdc_dest ) == NTGDI_OBJ_MEMDC)
623 BITMAP bm;
624 HBITMAP bmp = NtGdiGetDCObject( hdc_dest, NTGDI_OBJ_SURF );
625 alpha_blend = NtGdiExtGetObjectW( bmp, sizeof(bm), &bm ) && bm.bmBitsPixel > 8;
627 if (alpha_blend)
629 NtGdiSelectBitmap( mem_dc, obj->frame.alpha );
630 if (NtGdiAlphaBlend( hdc_dest, x, y, width, height, mem_dc,
631 0, 0, obj->frame.width, obj->frame.height,
632 MAKEFOURCC( AC_SRC_OVER, 0, 255, AC_SRC_ALPHA ), 0 ))
633 goto done;
637 if (flags & DI_MASK)
639 DWORD rop = (flags & DI_IMAGE) ? SRCAND : SRCCOPY;
640 NtGdiSelectBitmap( mem_dc, obj->frame.mask );
641 NtGdiStretchBlt( hdc_dest, x, y, width, height,
642 mem_dc, 0, 0, obj->frame.width, obj->frame.height, rop, 0 );
645 if (flags & DI_IMAGE)
647 if (obj->frame.color)
649 DWORD rop = (flags & DI_MASK) ? SRCINVERT : SRCCOPY;
650 NtGdiSelectBitmap( mem_dc, obj->frame.color );
651 NtGdiStretchBlt( hdc_dest, x, y, width, height,
652 mem_dc, 0, 0, obj->frame.width, obj->frame.height, rop, 0 );
654 else
656 DWORD rop = (flags & DI_MASK) ? SRCINVERT : SRCCOPY;
657 NtGdiSelectBitmap( mem_dc, obj->frame.mask );
658 NtGdiStretchBlt( hdc_dest, x, y, width, height,
659 mem_dc, 0, obj->frame.height, obj->frame.width,
660 obj->frame.height, rop, 0 );
664 done:
665 if (offscreen_bitmap) NtGdiBitBlt( hdc, x0, y0, width, height, hdc_dest, 0, 0, SRCCOPY, 0, 0 );
667 NtGdiGetAndSetDCDword( hdc, NtGdiSetTextColor, old_fg, NULL );
668 NtGdiGetAndSetDCDword( hdc, NtGdiSetBkColor, old_bg, NULL );
669 nStretchMode = set_stretch_blt_mode( hdc, nStretchMode );
671 result = TRUE;
672 if (hdc_dest != hdc) NtGdiDeleteObjectApp( hdc_dest );
673 if (offscreen_bitmap) NtGdiDeleteObjectApp( offscreen_bitmap );
674 failed:
675 NtGdiDeleteObjectApp( mem_dc );
676 release_user_handle_ptr( obj );
677 return result;
680 ULONG_PTR get_icon_param( HICON handle )
682 ULONG_PTR ret = 0;
683 struct cursoricon_object *obj = get_user_handle_ptr( handle, NTUSER_OBJ_ICON );
685 if (obj == OBJ_OTHER_PROCESS) WARN( "icon handle %p from other process\n", handle );
686 else if (obj)
688 ret = obj->param;
689 release_user_handle_ptr( obj );
691 return ret;
694 ULONG_PTR set_icon_param( HICON handle, ULONG_PTR param )
696 ULONG_PTR ret = 0;
697 struct cursoricon_object *obj = get_user_handle_ptr( handle, NTUSER_OBJ_ICON );
699 if (obj == OBJ_OTHER_PROCESS) WARN( "icon handle %p from other process\n", handle );
700 else if (obj)
702 ret = obj->param;
703 obj->param = param;
704 release_user_handle_ptr( obj );
706 return ret;
709 /******************************************************************************
710 * CopyImage (win32u.so)
712 HANDLE WINAPI CopyImage( HANDLE hwnd, UINT type, INT dx, INT dy, UINT flags )
714 void *ret_ptr;
715 ULONG ret_len;
716 NTSTATUS ret;
717 struct copy_image_params params =
718 { .hwnd = hwnd, .type = type, .dx = dx, .dy = dy, .flags = flags };
720 ret = KeUserModeCallback( NtUserCopyImage, &params, sizeof(params), &ret_ptr, &ret_len );
721 return UlongToHandle( ret );
724 /******************************************************************************
725 * LoadImage (win32u.so)
727 HANDLE WINAPI LoadImageW( HINSTANCE hinst, const WCHAR *name, UINT type,
728 INT dx, INT dy, UINT flags )
730 void *ret_ptr;
731 ULONG ret_len;
732 NTSTATUS ret;
733 struct load_image_params params =
734 { .hinst = hinst, .name = name, .type = type, .dx = dx, .dy = dy, .flags = flags };
736 if (HIWORD(name))
738 ERR( "name %s not supported in Unix modules\n", debugstr_w( name ));
739 return 0;
741 ret = KeUserModeCallback( NtUserLoadImage, &params, sizeof(params), &ret_ptr, &ret_len );
742 return UlongToHandle( ret );