user32: Add FIXMEs for unsupported animated cursor data.
[wine] / dlls / user32 / cursoricon.c
1 /*
2  * Cursor and icon support
3  *
4  * Copyright 1995 Alexandre Julliard
5  *           1996 Martin Von Loewis
6  *           1997 Alex Korobka
7  *           1998 Turchanov Sergey
8  *           2007 Henri Verbeet
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24
25 #include "config.h"
26 #include "wine/port.h"
27
28 #include <assert.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include <stdlib.h>
32
33 #include "windef.h"
34 #include "winbase.h"
35 #include "wingdi.h"
36 #include "winerror.h"
37 #include "winnls.h"
38 #include "wine/exception.h"
39 #include "wine/server.h"
40 #include "controls.h"
41 #include "win.h"
42 #include "user_private.h"
43 #include "wine/list.h"
44 #include "wine/unicode.h"
45 #include "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(cursor);
48 WINE_DECLARE_DEBUG_CHANNEL(icon);
49 WINE_DECLARE_DEBUG_CHANNEL(resource);
50
51 #include "pshpack1.h"
52
53 typedef struct {
54     BYTE bWidth;
55     BYTE bHeight;
56     BYTE bColorCount;
57     BYTE bReserved;
58     WORD xHotspot;
59     WORD yHotspot;
60     DWORD dwDIBSize;
61     DWORD dwDIBOffset;
62 } CURSORICONFILEDIRENTRY;
63
64 typedef struct
65 {
66     WORD                idReserved;
67     WORD                idType;
68     WORD                idCount;
69     CURSORICONFILEDIRENTRY  idEntries[1];
70 } CURSORICONFILEDIR;
71
72 #include "poppack.h"
73
74 static HDC screen_dc;
75
76 static const WCHAR DISPLAYW[] = {'D','I','S','P','L','A','Y',0};
77
78 static struct list icon_cache = LIST_INIT( icon_cache );
79
80 /**********************************************************************
81  * User objects management
82  */
83
84 struct cursoricon_frame
85 {
86     HBITMAP            color;    /* color bitmap */
87     HBITMAP            alpha;    /* pre-multiplied alpha bitmap for 32-bpp icons */
88     HBITMAP            mask;     /* mask bitmap (followed by color for 1-bpp icons) */
89 };
90
91 struct cursoricon_object
92 {
93     struct user_object      obj;        /* object header */
94     struct list             entry;      /* entry in shared icons list */
95     ULONG_PTR               param;      /* opaque param used by 16-bit code */
96     HMODULE                 module;     /* module for icons loaded from resources */
97     LPWSTR                  resname;    /* resource name for icons loaded from resources */
98     HRSRC                   rsrc;       /* resource for shared icons */
99     BOOL                    is_icon;    /* whether icon or cursor */
100     UINT                    width;
101     UINT                    height;
102     POINT                   hotspot;
103     UINT                    num_frames; /* number of frames in the icon/cursor */
104     UINT                    num_steps;  /* number of sequence steps in the icon/cursor */
105     UINT                    delay;      /* delay between frames (in jiffies) */
106     struct cursoricon_frame frames[1];  /* icon frame information */
107 };
108
109 static HICON alloc_icon_handle( UINT num_frames )
110 {
111     struct cursoricon_object *obj = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
112                                                FIELD_OFFSET( struct cursoricon_object, frames[num_frames] ));
113
114     if (!obj) return 0;
115     obj->delay = 0;
116     obj->num_steps = num_frames; /* changed later for some animated cursors */
117     obj->num_frames = num_frames;
118     return alloc_user_handle( &obj->obj, USER_ICON );
119 }
120
121 static struct cursoricon_object *get_icon_ptr( HICON handle )
122 {
123     struct cursoricon_object *obj = get_user_handle_ptr( handle, USER_ICON );
124     if (obj == OBJ_OTHER_PROCESS)
125     {
126         WARN( "icon handle %p from other process\n", handle );
127         obj = NULL;
128     }
129     return obj;
130 }
131
132 static void release_icon_ptr( HICON handle, struct cursoricon_object *ptr )
133 {
134     release_user_handle_ptr( ptr );
135 }
136
137 static BOOL free_icon_handle( HICON handle )
138 {
139     struct cursoricon_object *obj = free_user_handle( handle, USER_ICON );
140
141     if (obj == OBJ_OTHER_PROCESS) WARN( "icon handle %p from other process\n", handle );
142     else if (obj)
143     {
144         ULONG_PTR param = obj->param;
145         UINT i;
146
147         assert( !obj->rsrc );  /* shared icons can't be freed */
148
149         for (i=0; i<obj->num_frames; i++)
150         {
151             if (obj->frames[i].alpha) DeleteObject( obj->frames[i].alpha );
152             if (obj->frames[i].color) DeleteObject( obj->frames[i].color );
153             DeleteObject( obj->frames[i].mask );
154         }
155         if (!IS_INTRESOURCE( obj->resname )) HeapFree( GetProcessHeap(), 0, obj->resname );
156         HeapFree( GetProcessHeap(), 0, obj );
157         if (wow_handlers.free_icon_param && param) wow_handlers.free_icon_param( param );
158         USER_Driver->pDestroyCursorIcon( handle );
159         return TRUE;
160     }
161     return FALSE;
162 }
163
164 ULONG_PTR get_icon_param( HICON handle )
165 {
166     ULONG_PTR ret = 0;
167     struct cursoricon_object *obj = get_user_handle_ptr( handle, USER_ICON );
168
169     if (obj == OBJ_OTHER_PROCESS) WARN( "icon handle %p from other process\n", handle );
170     else if (obj)
171     {
172         ret = obj->param;
173         release_user_handle_ptr( obj );
174     }
175     return ret;
176 }
177
178 ULONG_PTR set_icon_param( HICON handle, ULONG_PTR param )
179 {
180     ULONG_PTR ret = 0;
181     struct cursoricon_object *obj = get_user_handle_ptr( handle, USER_ICON );
182
183     if (obj == OBJ_OTHER_PROCESS) WARN( "icon handle %p from other process\n", handle );
184     else if (obj)
185     {
186         ret = obj->param;
187         obj->param = param;
188         release_user_handle_ptr( obj );
189     }
190     return ret;
191 }
192
193
194 /***********************************************************************
195  *             map_fileW
196  *
197  * Helper function to map a file to memory:
198  *  name                        -       file name
199  *  [RETURN] ptr                -       pointer to mapped file
200  *  [RETURN] filesize           -       pointer size of file to be stored if not NULL
201  */
202 static void *map_fileW( LPCWSTR name, LPDWORD filesize )
203 {
204     HANDLE hFile, hMapping;
205     LPVOID ptr = NULL;
206
207     hFile = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL,
208                          OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0 );
209     if (hFile != INVALID_HANDLE_VALUE)
210     {
211         hMapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
212         if (hMapping)
213         {
214             ptr = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
215             CloseHandle( hMapping );
216             if (filesize)
217                 *filesize = GetFileSize( hFile, NULL );
218         }
219         CloseHandle( hFile );
220     }
221     return ptr;
222 }
223
224
225 /***********************************************************************
226  *          get_dib_width_bytes
227  *
228  * Return the width of a DIB bitmap in bytes. DIB bitmap data is 32-bit aligned.
229  */
230 static int get_dib_width_bytes( int width, int depth )
231 {
232     int words;
233
234     switch(depth)
235     {
236     case 1:  words = (width + 31) / 32; break;
237     case 4:  words = (width + 7) / 8; break;
238     case 8:  words = (width + 3) / 4; break;
239     case 15:
240     case 16: words = (width + 1) / 2; break;
241     case 24: words = (width * 3 + 3)/4; break;
242     default:
243         WARN("(%d): Unsupported depth\n", depth );
244         /* fall through */
245     case 32:
246         words = width;
247     }
248     return 4 * words;
249 }
250
251
252 /***********************************************************************
253  *           bitmap_info_size
254  *
255  * Return the size of the bitmap info structure including color table.
256  */
257 static int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
258 {
259     unsigned int colors, size, masks = 0;
260
261     if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
262     {
263         const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
264         colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
265         return sizeof(BITMAPCOREHEADER) + colors *
266              ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
267     }
268     else  /* assume BITMAPINFOHEADER */
269     {
270         colors = info->bmiHeader.biClrUsed;
271         if (colors > 256) /* buffer overflow otherwise */
272                 colors = 256;
273         if (!colors && (info->bmiHeader.biBitCount <= 8))
274             colors = 1 << info->bmiHeader.biBitCount;
275         if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
276         size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
277         return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
278     }
279 }
280
281
282 /***********************************************************************
283  *             copy_bitmap
284  *
285  * Helper function to duplicate a bitmap.
286  */
287 static HBITMAP copy_bitmap( HBITMAP bitmap )
288 {
289     HDC src, dst = 0;
290     HBITMAP new_bitmap = 0;
291     BITMAP bmp;
292
293     if (!bitmap) return 0;
294     if (!GetObjectW( bitmap, sizeof(bmp), &bmp )) return 0;
295
296     if ((src = CreateCompatibleDC( 0 )) && (dst = CreateCompatibleDC( 0 )))
297     {
298         SelectObject( src, bitmap );
299         if ((new_bitmap = CreateCompatibleBitmap( src, bmp.bmWidth, bmp.bmHeight )))
300         {
301             SelectObject( dst, new_bitmap );
302             BitBlt( dst, 0, 0, bmp.bmWidth, bmp.bmHeight, src, 0, 0, SRCCOPY );
303         }
304     }
305     DeleteDC( dst );
306     DeleteDC( src );
307     return new_bitmap;
308 }
309
310
311 /***********************************************************************
312  *          is_dib_monochrome
313  *
314  * Returns whether a DIB can be converted to a monochrome DDB.
315  *
316  * A DIB can be converted if its color table contains only black and
317  * white. Black must be the first color in the color table.
318  *
319  * Note : If the first color in the color table is white followed by
320  *        black, we can't convert it to a monochrome DDB with
321  *        SetDIBits, because black and white would be inverted.
322  */
323 static BOOL is_dib_monochrome( const BITMAPINFO* info )
324 {
325     if (info->bmiHeader.biBitCount != 1) return FALSE;
326
327     if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
328     {
329         const RGBTRIPLE *rgb = ((const BITMAPCOREINFO*)info)->bmciColors;
330
331         /* Check if the first color is black */
332         if ((rgb->rgbtRed == 0) && (rgb->rgbtGreen == 0) && (rgb->rgbtBlue == 0))
333         {
334             rgb++;
335
336             /* Check if the second color is white */
337             return ((rgb->rgbtRed == 0xff) && (rgb->rgbtGreen == 0xff)
338                  && (rgb->rgbtBlue == 0xff));
339         }
340         else return FALSE;
341     }
342     else  /* assume BITMAPINFOHEADER */
343     {
344         const RGBQUAD *rgb = info->bmiColors;
345
346         /* Check if the first color is black */
347         if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) &&
348             (rgb->rgbBlue == 0) && (rgb->rgbReserved == 0))
349         {
350             rgb++;
351
352             /* Check if the second color is white */
353             return ((rgb->rgbRed == 0xff) && (rgb->rgbGreen == 0xff)
354                  && (rgb->rgbBlue == 0xff) && (rgb->rgbReserved == 0));
355         }
356         else return FALSE;
357     }
358 }
359
360 /***********************************************************************
361  *           DIB_GetBitmapInfo
362  *
363  * Get the info from a bitmap header.
364  * Return 1 for INFOHEADER, 0 for COREHEADER, -1 in case of failure.
365  */
366 static int DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width,
367                               LONG *height, WORD *bpp, DWORD *compr )
368 {
369     if (header->biSize == sizeof(BITMAPCOREHEADER))
370     {
371         const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header;
372         *width  = core->bcWidth;
373         *height = core->bcHeight;
374         *bpp    = core->bcBitCount;
375         *compr  = 0;
376         return 0;
377     }
378     else if (header->biSize == sizeof(BITMAPINFOHEADER) ||
379              header->biSize == sizeof(BITMAPV4HEADER) ||
380              header->biSize == sizeof(BITMAPV5HEADER))
381     {
382         *width  = header->biWidth;
383         *height = header->biHeight;
384         *bpp    = header->biBitCount;
385         *compr  = header->biCompression;
386         return 1;
387     }
388     WARN("unknown/wrong size (%u) for header\n", header->biSize);
389     return -1;
390 }
391
392 /**********************************************************************
393  *              get_icon_size
394  */
395 BOOL get_icon_size( HICON handle, SIZE *size )
396 {
397     struct cursoricon_object *info;
398
399     if (!(info = get_icon_ptr( handle ))) return FALSE;
400     size->cx = info->width;
401     size->cy = info->height;
402     release_icon_ptr( handle, info );
403     return TRUE;
404 }
405
406 /*
407  *  The following macro functions account for the irregularities of
408  *   accessing cursor and icon resources in files and resource entries.
409  */
410 typedef BOOL (*fnGetCIEntry)( LPCVOID dir, int n,
411                               int *width, int *height, int *bits );
412
413 /**********************************************************************
414  *          CURSORICON_FindBestIcon
415  *
416  * Find the icon closest to the requested size and bit depth.
417  */
418 static int CURSORICON_FindBestIcon( LPCVOID dir, fnGetCIEntry get_entry,
419                                     int width, int height, int depth, UINT loadflags )
420 {
421     int i, cx, cy, bits, bestEntry = -1;
422     UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
423     UINT iTempXDiff, iTempYDiff, iTempColorDiff;
424
425     /* Find Best Fit */
426     iTotalDiff = 0xFFFFFFFF;
427     iColorDiff = 0xFFFFFFFF;
428
429     if (loadflags & LR_DEFAULTSIZE)
430     {
431         if (!width) width = GetSystemMetrics( SM_CXICON );
432         if (!height) height = GetSystemMetrics( SM_CYICON );
433     }
434     else if (!width && !height)
435     {
436         /* use the size of the first entry */
437         if (!get_entry( dir, 0, &width, &height, &bits )) return -1;
438         iTotalDiff = 0;
439     }
440
441     for ( i = 0; iTotalDiff && get_entry( dir, i, &cx, &cy, &bits ); i++ )
442     {
443         iTempXDiff = abs(width - cx);
444         iTempYDiff = abs(height - cy);
445
446         if(iTotalDiff > (iTempXDiff + iTempYDiff))
447         {
448             iXDiff = iTempXDiff;
449             iYDiff = iTempYDiff;
450             iTotalDiff = iXDiff + iYDiff;
451         }
452     }
453
454     /* Find Best Colors for Best Fit */
455     for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
456     {
457         if(abs(width - cx) == iXDiff && abs(height - cy) == iYDiff)
458         {
459             iTempColorDiff = abs(depth - bits);
460             if(iColorDiff > iTempColorDiff)
461             {
462                 bestEntry = i;
463                 iColorDiff = iTempColorDiff;
464             }
465         }
466     }
467
468     return bestEntry;
469 }
470
471 static BOOL CURSORICON_GetResIconEntry( LPCVOID dir, int n,
472                                         int *width, int *height, int *bits )
473 {
474     const CURSORICONDIR *resdir = dir;
475     const ICONRESDIR *icon;
476
477     if ( resdir->idCount <= n )
478         return FALSE;
479     icon = &resdir->idEntries[n].ResInfo.icon;
480     *width = icon->bWidth;
481     *height = icon->bHeight;
482     *bits = resdir->idEntries[n].wBitCount;
483     return TRUE;
484 }
485
486 /**********************************************************************
487  *          CURSORICON_FindBestCursor
488  *
489  * Find the cursor closest to the requested size.
490  *
491  * FIXME: parameter 'color' ignored.
492  */
493 static int CURSORICON_FindBestCursor( LPCVOID dir, fnGetCIEntry get_entry,
494                                       int width, int height, int depth, UINT loadflags )
495 {
496     int i, maxwidth, maxheight, cx, cy, bits, bestEntry = -1;
497
498     if (loadflags & LR_DEFAULTSIZE)
499     {
500         if (!width) width = GetSystemMetrics( SM_CXCURSOR );
501         if (!height) height = GetSystemMetrics( SM_CYCURSOR );
502     }
503     else if (!width && !height)
504     {
505         /* use the first entry */
506         if (!get_entry( dir, 0, &width, &height, &bits )) return -1;
507         return 0;
508     }
509
510     /* Double height to account for AND and XOR masks */
511
512     height *= 2;
513
514     /* First find the largest one smaller than or equal to the requested size*/
515
516     maxwidth = maxheight = 0;
517     for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
518     {
519         if ((cx <= width) && (cy <= height) &&
520             (cx > maxwidth) && (cy > maxheight))
521         {
522             bestEntry = i;
523             maxwidth  = cx;
524             maxheight = cy;
525         }
526     }
527     if (bestEntry != -1) return bestEntry;
528
529     /* Now find the smallest one larger than the requested size */
530
531     maxwidth = maxheight = 255;
532     for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
533     {
534         if (((cx < maxwidth) && (cy < maxheight)) || (bestEntry == -1))
535         {
536             bestEntry = i;
537             maxwidth  = cx;
538             maxheight = cy;
539         }
540     }
541
542     return bestEntry;
543 }
544
545 static BOOL CURSORICON_GetResCursorEntry( LPCVOID dir, int n,
546                                           int *width, int *height, int *bits )
547 {
548     const CURSORICONDIR *resdir = dir;
549     const CURSORDIR *cursor;
550
551     if ( resdir->idCount <= n )
552         return FALSE;
553     cursor = &resdir->idEntries[n].ResInfo.cursor;
554     *width = cursor->wWidth;
555     *height = cursor->wHeight;
556     *bits = resdir->idEntries[n].wBitCount;
557     return TRUE;
558 }
559
560 static const CURSORICONDIRENTRY *CURSORICON_FindBestIconRes( const CURSORICONDIR * dir,
561                                                              int width, int height, int depth,
562                                                              UINT loadflags )
563 {
564     int n;
565
566     n = CURSORICON_FindBestIcon( dir, CURSORICON_GetResIconEntry,
567                                  width, height, depth, loadflags );
568     if ( n < 0 )
569         return NULL;
570     return &dir->idEntries[n];
571 }
572
573 static const CURSORICONDIRENTRY *CURSORICON_FindBestCursorRes( const CURSORICONDIR *dir,
574                                                                int width, int height, int depth,
575                                                                UINT loadflags )
576 {
577     int n = CURSORICON_FindBestCursor( dir, CURSORICON_GetResCursorEntry,
578                                        width, height, depth, loadflags );
579     if ( n < 0 )
580         return NULL;
581     return &dir->idEntries[n];
582 }
583
584 static BOOL CURSORICON_GetFileEntry( LPCVOID dir, int n,
585                                      int *width, int *height, int *bits )
586 {
587     const CURSORICONFILEDIR *filedir = dir;
588     const CURSORICONFILEDIRENTRY *entry;
589     const BITMAPINFOHEADER *info;
590
591     if ( filedir->idCount <= n )
592         return FALSE;
593     entry = &filedir->idEntries[n];
594     /* FIXME: check against file size */
595     info = (const BITMAPINFOHEADER *)((const char *)dir + entry->dwDIBOffset);
596     *width = entry->bWidth;
597     *height = entry->bHeight;
598     *bits = info->biBitCount;
599     return TRUE;
600 }
601
602 static const CURSORICONFILEDIRENTRY *CURSORICON_FindBestCursorFile( const CURSORICONFILEDIR *dir,
603                                                                     int width, int height, int depth,
604                                                                     UINT loadflags )
605 {
606     int n = CURSORICON_FindBestCursor( dir, CURSORICON_GetFileEntry,
607                                        width, height, depth, loadflags );
608     if ( n < 0 )
609         return NULL;
610     return &dir->idEntries[n];
611 }
612
613 static const CURSORICONFILEDIRENTRY *CURSORICON_FindBestIconFile( const CURSORICONFILEDIR *dir,
614                                                                   int width, int height, int depth,
615                                                                   UINT loadflags )
616 {
617     int n = CURSORICON_FindBestIcon( dir, CURSORICON_GetFileEntry,
618                                      width, height, depth, loadflags );
619     if ( n < 0 )
620         return NULL;
621     return &dir->idEntries[n];
622 }
623
624 /***********************************************************************
625  *          bmi_has_alpha
626  */
627 static BOOL bmi_has_alpha( const BITMAPINFO *info, const void *bits )
628 {
629     int i;
630     BOOL has_alpha = FALSE;
631     const unsigned char *ptr = bits;
632
633     if (info->bmiHeader.biBitCount != 32) return FALSE;
634     for (i = 0; i < info->bmiHeader.biWidth * abs(info->bmiHeader.biHeight); i++, ptr += 4)
635         if ((has_alpha = (ptr[3] != 0))) break;
636     return has_alpha;
637 }
638
639 /***********************************************************************
640  *          create_alpha_bitmap
641  *
642  * Create the alpha bitmap for a 32-bpp icon that has an alpha channel.
643  */
644 static HBITMAP create_alpha_bitmap( HBITMAP color, HBITMAP mask,
645                                     const BITMAPINFO *src_info, const void *color_bits )
646 {
647     HBITMAP alpha = 0;
648     BITMAPINFO *info = NULL;
649     BITMAP bm;
650     HDC hdc;
651     void *bits;
652     unsigned char *ptr;
653     int i;
654
655     if (!GetObjectW( color, sizeof(bm), &bm )) return 0;
656     if (bm.bmBitsPixel != 32) return 0;
657
658     if (!(hdc = CreateCompatibleDC( 0 ))) return 0;
659     if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
660     info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
661     info->bmiHeader.biWidth = bm.bmWidth;
662     info->bmiHeader.biHeight = -bm.bmHeight;
663     info->bmiHeader.biPlanes = 1;
664     info->bmiHeader.biBitCount = 32;
665     info->bmiHeader.biCompression = BI_RGB;
666     info->bmiHeader.biSizeImage = bm.bmWidth * bm.bmHeight * 4;
667     info->bmiHeader.biXPelsPerMeter = 0;
668     info->bmiHeader.biYPelsPerMeter = 0;
669     info->bmiHeader.biClrUsed = 0;
670     info->bmiHeader.biClrImportant = 0;
671     if (!(alpha = CreateDIBSection( hdc, info, DIB_RGB_COLORS, &bits, NULL, 0 ))) goto done;
672
673     if (src_info)
674     {
675         SelectObject( hdc, alpha );
676         StretchDIBits( hdc, 0, 0, bm.bmWidth, bm.bmHeight,
677                        0, 0, src_info->bmiHeader.biWidth, src_info->bmiHeader.biHeight,
678                        color_bits, src_info, DIB_RGB_COLORS, SRCCOPY );
679
680     }
681     else
682     {
683         GetDIBits( hdc, color, 0, bm.bmHeight, bits, info, DIB_RGB_COLORS );
684         if (!bmi_has_alpha( info, bits ))
685         {
686             DeleteObject( alpha );
687             alpha = 0;
688             goto done;
689         }
690     }
691
692     /* pre-multiply by alpha */
693     for (i = 0, ptr = bits; i < bm.bmWidth * bm.bmHeight; i++, ptr += 4)
694     {
695         unsigned int alpha = ptr[3];
696         ptr[0] = ptr[0] * alpha / 255;
697         ptr[1] = ptr[1] * alpha / 255;
698         ptr[2] = ptr[2] * alpha / 255;
699     }
700
701 done:
702     DeleteDC( hdc );
703     HeapFree( GetProcessHeap(), 0, info );
704     return alpha;
705 }
706
707
708 /***********************************************************************
709  *          create_icon_bitmaps
710  *
711  * Create the color, mask and alpha bitmaps from the DIB info.
712  */
713 static BOOL create_icon_bitmaps( const BITMAPINFO *bmi, int width, int height,
714                                  HBITMAP *color, HBITMAP *mask, HBITMAP *alpha )
715 {
716     BOOL monochrome = is_dib_monochrome( bmi );
717     unsigned int size = bitmap_info_size( bmi, DIB_RGB_COLORS );
718     BITMAPINFO *info;
719     const void *color_bits, *mask_bits;
720     BOOL ret = FALSE;
721     HDC hdc = 0;
722
723     if (!(info = HeapAlloc( GetProcessHeap(), 0, max( size, FIELD_OFFSET( BITMAPINFO, bmiColors[2] )))))
724         return FALSE;
725     if (!(hdc = CreateCompatibleDC( 0 ))) goto done;
726
727     memcpy( info, bmi, size );
728     info->bmiHeader.biHeight /= 2;
729
730     color_bits = (const char*)bmi + size;
731     mask_bits = (const char*)color_bits +
732         get_dib_width_bytes( bmi->bmiHeader.biWidth,
733                              bmi->bmiHeader.biBitCount ) * abs(info->bmiHeader.biHeight);
734
735     *alpha = 0;
736     if (monochrome)
737     {
738         if (!(*mask = CreateBitmap( width, height * 2, 1, 1, NULL ))) goto done;
739         *color = 0;
740
741         /* copy color data into second half of mask bitmap */
742         SelectObject( hdc, *mask );
743         StretchDIBits( hdc, 0, height, width, height,
744                        0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight,
745                        color_bits, info, DIB_RGB_COLORS, SRCCOPY );
746     }
747     else
748     {
749         if (!(*mask = CreateBitmap( width, height, 1, 1, NULL ))) goto done;
750         if (!(*color = CreateBitmap( width, height, GetDeviceCaps( screen_dc, PLANES ),
751                                      GetDeviceCaps( screen_dc, BITSPIXEL ), NULL )))
752         {
753             DeleteObject( *mask );
754             goto done;
755         }
756         SelectObject( hdc, *color );
757         StretchDIBits( hdc, 0, 0, width, height,
758                        0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight,
759                        color_bits, info, DIB_RGB_COLORS, SRCCOPY );
760
761         if (bmi_has_alpha( info, color_bits ))
762             *alpha = create_alpha_bitmap( *color, *mask, info, color_bits );
763
764         /* convert info to monochrome to copy the mask */
765         info->bmiHeader.biBitCount = 1;
766         if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
767         {
768             RGBQUAD *rgb = info->bmiColors;
769
770             info->bmiHeader.biClrUsed = info->bmiHeader.biClrImportant = 2;
771             rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
772             rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
773             rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
774         }
775         else
776         {
777             RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)info) + 1);
778
779             rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
780             rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
781         }
782     }
783
784     SelectObject( hdc, *mask );
785     StretchDIBits( hdc, 0, 0, width, height,
786                    0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight,
787                    mask_bits, info, DIB_RGB_COLORS, SRCCOPY );
788     ret = TRUE;
789
790 done:
791     DeleteDC( hdc );
792     HeapFree( GetProcessHeap(), 0, info );
793     return ret;
794 }
795
796 static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi, HMODULE module, LPCWSTR resname, HRSRC rsrc,
797                                            POINT hotspot, BOOL bIcon, INT width, INT height, UINT cFlag )
798 {
799     HICON hObj;
800     HBITMAP color = 0, mask = 0, alpha = 0;
801     BOOL do_stretch;
802
803     /* Check bitmap header */
804
805     if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
806          (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)  ||
807           bmi->bmiHeader.biCompression != BI_RGB) )
808     {
809           WARN_(cursor)("\tinvalid resource bitmap header.\n");
810           return 0;
811     }
812
813     if (cFlag & LR_DEFAULTSIZE)
814     {
815         if (!width) width = GetSystemMetrics( bIcon ? SM_CXICON : SM_CXCURSOR );
816         if (!height) height = GetSystemMetrics( bIcon ? SM_CYICON : SM_CYCURSOR );
817     }
818     else
819     {
820         if (!width) width = bmi->bmiHeader.biWidth;
821         if (!height) height = bmi->bmiHeader.biHeight/2;
822     }
823     do_stretch = (bmi->bmiHeader.biHeight/2 != height) ||
824                  (bmi->bmiHeader.biWidth != width);
825
826     /* Scale the hotspot */
827     if (bIcon)
828     {
829         hotspot.x = width / 2;
830         hotspot.y = height / 2;
831     }
832     else if (do_stretch)
833     {
834         hotspot.x = (hotspot.x * width) / bmi->bmiHeader.biWidth;
835         hotspot.y = (hotspot.y * height) / (bmi->bmiHeader.biHeight / 2);
836     }
837
838     if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
839     if (!screen_dc) return 0;
840
841     if (!create_icon_bitmaps( bmi, width, height, &color, &mask, &alpha )) return 0;
842
843     hObj = alloc_icon_handle(1);
844     if (hObj)
845     {
846         struct cursoricon_object *info = get_icon_ptr( hObj );
847
848         info->is_icon = bIcon;
849         info->module  = module;
850         info->hotspot = hotspot;
851         info->width   = width;
852         info->height  = height;
853         info->frames[0].color = color;
854         info->frames[0].mask  = mask;
855         info->frames[0].alpha = alpha;
856         if (!IS_INTRESOURCE(resname))
857         {
858             info->resname = HeapAlloc( GetProcessHeap(), 0, (strlenW(resname) + 1) * sizeof(WCHAR) );
859             if (info->resname) strcpyW( info->resname, resname );
860         }
861         else info->resname = MAKEINTRESOURCEW( LOWORD(resname) );
862
863         if (module && (cFlag & LR_SHARED))
864         {
865             info->rsrc = rsrc;
866             list_add_head( &icon_cache, &info->entry );
867         }
868         release_icon_ptr( hObj, info );
869         USER_Driver->pCreateCursorIcon( hObj );
870     }
871     else
872     {
873         DeleteObject( color );
874         DeleteObject( alpha );
875         DeleteObject( mask );
876     }
877     return hObj;
878 }
879
880
881 /**********************************************************************
882  *          .ANI cursor support
883  */
884 #define RIFF_FOURCC( c0, c1, c2, c3 ) \
885         ( (DWORD)(BYTE)(c0) | ( (DWORD)(BYTE)(c1) << 8 ) | \
886         ( (DWORD)(BYTE)(c2) << 16 ) | ( (DWORD)(BYTE)(c3) << 24 ) )
887
888 #define ANI_RIFF_ID RIFF_FOURCC('R', 'I', 'F', 'F')
889 #define ANI_LIST_ID RIFF_FOURCC('L', 'I', 'S', 'T')
890 #define ANI_ACON_ID RIFF_FOURCC('A', 'C', 'O', 'N')
891 #define ANI_anih_ID RIFF_FOURCC('a', 'n', 'i', 'h')
892 #define ANI_seq__ID RIFF_FOURCC('s', 'e', 'q', ' ')
893 #define ANI_fram_ID RIFF_FOURCC('f', 'r', 'a', 'm')
894 #define ANI_rate_ID RIFF_FOURCC('r', 'a', 't', 'e')
895
896 #define ANI_FLAG_ICON       0x1
897 #define ANI_FLAG_SEQUENCE   0x2
898
899 typedef struct {
900     DWORD header_size;
901     DWORD num_frames;
902     DWORD num_steps;
903     DWORD width;
904     DWORD height;
905     DWORD bpp;
906     DWORD num_planes;
907     DWORD display_rate;
908     DWORD flags;
909 } ani_header;
910
911 typedef struct {
912     DWORD           data_size;
913     const unsigned char   *data;
914 } riff_chunk_t;
915
916 static void dump_ani_header( const ani_header *header )
917 {
918     TRACE("     header size: %d\n", header->header_size);
919     TRACE("          frames: %d\n", header->num_frames);
920     TRACE("           steps: %d\n", header->num_steps);
921     TRACE("           width: %d\n", header->width);
922     TRACE("          height: %d\n", header->height);
923     TRACE("             bpp: %d\n", header->bpp);
924     TRACE("          planes: %d\n", header->num_planes);
925     TRACE("    display rate: %d\n", header->display_rate);
926     TRACE("           flags: 0x%08x\n", header->flags);
927 }
928
929
930 /*
931  * RIFF:
932  * DWORD "RIFF"
933  * DWORD size
934  * DWORD riff_id
935  * BYTE[] data
936  *
937  * LIST:
938  * DWORD "LIST"
939  * DWORD size
940  * DWORD list_id
941  * BYTE[] data
942  *
943  * CHUNK:
944  * DWORD chunk_id
945  * DWORD size
946  * BYTE[] data
947  */
948 static void riff_find_chunk( DWORD chunk_id, DWORD chunk_type, const riff_chunk_t *parent_chunk, riff_chunk_t *chunk )
949 {
950     const unsigned char *ptr = parent_chunk->data;
951     const unsigned char *end = parent_chunk->data + (parent_chunk->data_size - (2 * sizeof(DWORD)));
952
953     if (chunk_type == ANI_LIST_ID || chunk_type == ANI_RIFF_ID) end -= sizeof(DWORD);
954
955     while (ptr < end)
956     {
957         if ((!chunk_type && *(const DWORD *)ptr == chunk_id )
958                 || (chunk_type && *(const DWORD *)ptr == chunk_type && *((const DWORD *)ptr + 2) == chunk_id ))
959         {
960             ptr += sizeof(DWORD);
961             chunk->data_size = (*(const DWORD *)ptr + 1) & ~1;
962             ptr += sizeof(DWORD);
963             if (chunk_type == ANI_LIST_ID || chunk_type == ANI_RIFF_ID) ptr += sizeof(DWORD);
964             chunk->data = ptr;
965
966             return;
967         }
968
969         ptr += sizeof(DWORD);
970         ptr += (*(const DWORD *)ptr + 1) & ~1;
971         ptr += sizeof(DWORD);
972     }
973 }
974
975
976 /*
977  * .ANI layout:
978  *
979  * RIFF:'ACON'                  RIFF chunk
980  *     |- CHUNK:'anih'          Header
981  *     |- CHUNK:'seq '          Sequence information (optional)
982  *     \- LIST:'fram'           Frame list
983  *            |- CHUNK:icon     Cursor frames
984  *            |- CHUNK:icon
985  *            |- ...
986  *            \- CHUNK:icon
987  */
988 static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
989                                              INT width, INT height, INT depth, UINT loadflags )
990 {
991     struct cursoricon_object *info;
992     ani_header header = {0};
993     HCURSOR cursor = 0;
994     UINT i, error = 0;
995
996     riff_chunk_t root_chunk = { bits_size, bits };
997     riff_chunk_t ACON_chunk = {0};
998     riff_chunk_t anih_chunk = {0};
999     riff_chunk_t fram_chunk = {0};
1000     riff_chunk_t rate_chunk = {0};
1001     const unsigned char *icon_chunk;
1002     const unsigned char *icon_data;
1003
1004     TRACE("bits %p, bits_size %d\n", bits, bits_size);
1005
1006     riff_find_chunk( ANI_ACON_ID, ANI_RIFF_ID, &root_chunk, &ACON_chunk );
1007     if (!ACON_chunk.data)
1008     {
1009         ERR("Failed to get root chunk.\n");
1010         return 0;
1011     }
1012
1013     riff_find_chunk( ANI_anih_ID, 0, &ACON_chunk, &anih_chunk );
1014     if (!anih_chunk.data)
1015     {
1016         ERR("Failed to get 'anih' chunk.\n");
1017         return 0;
1018     }
1019     memcpy( &header, anih_chunk.data, sizeof(header) );
1020     dump_ani_header( &header );
1021
1022     if (!(header.flags & ANI_FLAG_ICON))
1023     {
1024         FIXME("Raw animated icon/cursor data is not currently supported.\n");
1025         return 0;
1026     }
1027
1028     if (header.flags & ANI_FLAG_SEQUENCE)
1029         FIXME("Animated icon/cursor sequence data is not currently supported, frames may appear out of sequence.\n");
1030
1031     riff_find_chunk( ANI_rate_ID, 0, &ACON_chunk, &rate_chunk );
1032     if (rate_chunk.data)
1033         FIXME("Animated icon/cursor multiple frame-frate data not currently supported.\n");
1034
1035     riff_find_chunk( ANI_fram_ID, ANI_LIST_ID, &ACON_chunk, &fram_chunk );
1036     if (!fram_chunk.data)
1037     {
1038         ERR("Failed to get icon list.\n");
1039         return 0;
1040     }
1041
1042     cursor = alloc_icon_handle( header.num_frames );
1043     if (!cursor) return 0;
1044
1045     info = get_icon_ptr( cursor );
1046     info->is_icon = FALSE;
1047     if (header.num_steps > header.num_frames)
1048     {
1049         FIXME("More steps than frames and sequence-based cursors not yet supported.\n");
1050         info->num_steps = header.num_frames;
1051     }
1052     else
1053         info->num_steps = header.num_steps;
1054
1055     /* The .ANI stores the display rate in jiffies (1/60s) */
1056     info->delay = header.display_rate;
1057
1058     icon_chunk = fram_chunk.data;
1059     icon_data = fram_chunk.data + (2 * sizeof(DWORD));
1060     for (i=0; i<header.num_frames; i++)
1061     {
1062         const DWORD chunk_size = *(const DWORD *)(icon_chunk + sizeof(DWORD));
1063         struct cursoricon_frame *frame = &info->frames[i];
1064         const CURSORICONFILEDIRENTRY *entry;
1065         const BITMAPINFO *bmi;
1066
1067         entry = CURSORICON_FindBestIconFile((const CURSORICONFILEDIR *) icon_data,
1068                                             width, height, depth, loadflags );
1069
1070         bmi = (const BITMAPINFO *) (icon_data + entry->dwDIBOffset);
1071         info->hotspot.x = entry->xHotspot;
1072         info->hotspot.y = entry->yHotspot;
1073         if (!header.width || !header.height)
1074         {
1075             header.width = entry->bWidth;
1076             header.height = entry->bHeight;
1077         }
1078
1079         /* Grab a frame from the animation */
1080         if (!create_icon_bitmaps( bmi, header.width, header.height,
1081             &frame->color, &frame->mask, &frame->alpha ))
1082         {
1083             FIXME_(cursor)("failed to convert animated cursor frame.\n");
1084             error = TRUE;
1085             if (i == 0)
1086             {
1087                 FIXME_(cursor)("Completely failed to create animated cursor!\n");
1088                 info->num_frames = 0;
1089                 release_icon_ptr( cursor, info );
1090                 free_icon_handle( cursor );
1091                 return 0;
1092             }
1093             break;
1094         }
1095
1096         /* Advance to the next chunk */
1097         icon_chunk += chunk_size + (2 * sizeof(DWORD));
1098         icon_data = icon_chunk + (2 * sizeof(DWORD));
1099     }
1100
1101     /* There was an error but we at least decoded the first frame, so just use that frame */
1102     if (error)
1103     {
1104         FIXME_(cursor)("Error creating animated cursor, only using first frame!\n");
1105         for (i=1; i<info->num_frames; i++)
1106         {
1107             if (info->frames[i].mask) DeleteObject( info->frames[i].mask );
1108             if (info->frames[i].color) DeleteObject( info->frames[i].color );
1109             if (info->frames[i].alpha) DeleteObject( info->frames[i].alpha );
1110         }
1111         info->num_frames = 1;
1112         info->num_steps = 1;
1113         info->delay = 0;
1114     }
1115     info->width = header.width;
1116     info->height = header.height;
1117     release_icon_ptr( cursor, info );
1118
1119     return cursor;
1120 }
1121
1122
1123 /**********************************************************************
1124  *              CreateIconFromResourceEx (USER32.@)
1125  *
1126  * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
1127  *        with cbSize parameter as well.
1128  */
1129 HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
1130                                        BOOL bIcon, DWORD dwVersion,
1131                                        INT width, INT height,
1132                                        UINT cFlag )
1133 {
1134     POINT hotspot;
1135     BITMAPINFO *bmi;
1136
1137     TRACE_(cursor)("%p (%u bytes), ver %08x, %ix%i %s %s\n",
1138                    bits, cbSize, dwVersion, width, height,
1139                    bIcon ? "icon" : "cursor", (cFlag & LR_MONOCHROME) ? "mono" : "" );
1140
1141     if (!bits) return 0;
1142
1143     if (dwVersion == 0x00020000)
1144     {
1145         FIXME_(cursor)("\t2.xx resources are not supported\n");
1146         return 0;
1147     }
1148
1149     /* Check if the resource is an animated icon/cursor */
1150     if (!memcmp(bits, "RIFF", 4))
1151         return CURSORICON_CreateIconFromANI( bits, cbSize, width, height, 0 /* default depth */, cFlag );
1152
1153     if (bIcon)
1154     {
1155         hotspot.x = width / 2;
1156         hotspot.y = height / 2;
1157         bmi = (BITMAPINFO *)bits;
1158     }
1159     else /* get the hotspot */
1160     {
1161         SHORT *pt = (SHORT *)bits;
1162         hotspot.x = pt[0];
1163         hotspot.y = pt[1];
1164         bmi = (BITMAPINFO *)(pt + 2);
1165     }
1166
1167     return CURSORICON_CreateIconFromBMI( bmi, NULL, NULL, NULL, hotspot, bIcon, width, height, cFlag );
1168 }
1169
1170
1171 /**********************************************************************
1172  *              CreateIconFromResource (USER32.@)
1173  */
1174 HICON WINAPI CreateIconFromResource( LPBYTE bits, UINT cbSize,
1175                                            BOOL bIcon, DWORD dwVersion)
1176 {
1177     return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
1178 }
1179
1180
1181 static HICON CURSORICON_LoadFromFile( LPCWSTR filename,
1182                              INT width, INT height, INT depth,
1183                              BOOL fCursor, UINT loadflags)
1184 {
1185     const CURSORICONFILEDIRENTRY *entry;
1186     const CURSORICONFILEDIR *dir;
1187     DWORD filesize = 0;
1188     HICON hIcon = 0;
1189     LPBYTE bits;
1190     POINT hotspot;
1191
1192     TRACE("loading %s\n", debugstr_w( filename ));
1193
1194     bits = map_fileW( filename, &filesize );
1195     if (!bits)
1196         return hIcon;
1197
1198     /* Check for .ani. */
1199     if (memcmp( bits, "RIFF", 4 ) == 0)
1200     {
1201         hIcon = CURSORICON_CreateIconFromANI( bits, filesize, width, height, depth, loadflags );
1202         goto end;
1203     }
1204
1205     dir = (const CURSORICONFILEDIR*) bits;
1206     if ( filesize < sizeof(*dir) )
1207         goto end;
1208
1209     if ( filesize < (sizeof(*dir) + sizeof(dir->idEntries[0])*(dir->idCount-1)) )
1210         goto end;
1211
1212     if ( fCursor )
1213         entry = CURSORICON_FindBestCursorFile( dir, width, height, depth, loadflags );
1214     else
1215         entry = CURSORICON_FindBestIconFile( dir, width, height, depth, loadflags );
1216
1217     if ( !entry )
1218         goto end;
1219
1220     /* check that we don't run off the end of the file */
1221     if ( entry->dwDIBOffset > filesize )
1222         goto end;
1223     if ( entry->dwDIBOffset + entry->dwDIBSize > filesize )
1224         goto end;
1225
1226     hotspot.x = entry->xHotspot;
1227     hotspot.y = entry->yHotspot;
1228     hIcon = CURSORICON_CreateIconFromBMI( (BITMAPINFO *)&bits[entry->dwDIBOffset], NULL, NULL, NULL,
1229                                           hotspot, !fCursor, width, height, loadflags );
1230 end:
1231     TRACE("loaded %s -> %p\n", debugstr_w( filename ), hIcon );
1232     UnmapViewOfFile( bits );
1233     return hIcon;
1234 }
1235
1236 /**********************************************************************
1237  *          CURSORICON_Load
1238  *
1239  * Load a cursor or icon from resource or file.
1240  */
1241 static HICON CURSORICON_Load(HINSTANCE hInstance, LPCWSTR name,
1242                              INT width, INT height, INT depth,
1243                              BOOL fCursor, UINT loadflags)
1244 {
1245     HANDLE handle = 0;
1246     HICON hIcon = 0;
1247     HRSRC hRsrc;
1248     const CURSORICONDIR *dir;
1249     const CURSORICONDIRENTRY *dirEntry;
1250     LPBYTE bits;
1251     WORD wResId;
1252     POINT hotspot;
1253
1254     TRACE("%p, %s, %dx%d, depth %d, fCursor %d, flags 0x%04x\n",
1255           hInstance, debugstr_w(name), width, height, depth, fCursor, loadflags);
1256
1257     if ( loadflags & LR_LOADFROMFILE )    /* Load from file */
1258         return CURSORICON_LoadFromFile( name, width, height, depth, fCursor, loadflags );
1259
1260     if (!hInstance) hInstance = user32_module;  /* Load OEM cursor/icon */
1261
1262     /* don't cache 16-bit instances (FIXME: should never get 16-bit instances in the first place) */
1263     if ((ULONG_PTR)hInstance >> 16 == 0) loadflags &= ~LR_SHARED;
1264
1265     /* Get directory resource ID */
1266
1267     if (!(hRsrc = FindResourceW( hInstance, name,
1268                                  (LPWSTR)(fCursor ? RT_GROUP_CURSOR : RT_GROUP_ICON) )))
1269         return 0;
1270
1271     /* Find the best entry in the directory */
1272
1273     if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
1274     if (!(dir = LockResource( handle ))) return 0;
1275     if (fCursor)
1276         dirEntry = CURSORICON_FindBestCursorRes( dir, width, height, depth, loadflags );
1277     else
1278         dirEntry = CURSORICON_FindBestIconRes( dir, width, height, depth, loadflags );
1279     if (!dirEntry) return 0;
1280     wResId = dirEntry->wResId;
1281     FreeResource( handle );
1282
1283     /* Load the resource */
1284
1285     if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
1286                                 (LPWSTR)(fCursor ? RT_CURSOR : RT_ICON) ))) return 0;
1287
1288     /* If shared icon, check whether it was already loaded */
1289     if (loadflags & LR_SHARED)
1290     {
1291         struct cursoricon_object *ptr;
1292
1293         USER_Lock();
1294         LIST_FOR_EACH_ENTRY( ptr, &icon_cache, struct cursoricon_object, entry )
1295         {
1296             if (ptr->module != hInstance) continue;
1297             if (ptr->rsrc != hRsrc) continue;
1298             hIcon = ptr->obj.handle;
1299             break;
1300         }
1301         USER_Unlock();
1302         if (hIcon) return hIcon;
1303     }
1304
1305     if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
1306     bits = LockResource( handle );
1307
1308     if (!fCursor)
1309     {
1310         hotspot.x = width / 2;
1311         hotspot.y = height / 2;
1312     }
1313     else /* get the hotspot */
1314     {
1315         SHORT *pt = (SHORT *)bits;
1316         hotspot.x = pt[0];
1317         hotspot.y = pt[1];
1318         bits += 2 * sizeof(SHORT);
1319     }
1320     hIcon = CURSORICON_CreateIconFromBMI( (BITMAPINFO *)bits, hInstance, name, hRsrc,
1321                                           hotspot, !fCursor, width, height, loadflags );
1322     FreeResource( handle );
1323     return hIcon;
1324 }
1325
1326
1327 /***********************************************************************
1328  *              CreateCursor (USER32.@)
1329  */
1330 HCURSOR WINAPI CreateCursor( HINSTANCE hInstance,
1331                                  INT xHotSpot, INT yHotSpot,
1332                                  INT nWidth, INT nHeight,
1333                                  LPCVOID lpANDbits, LPCVOID lpXORbits )
1334 {
1335     ICONINFO info;
1336     HCURSOR hCursor;
1337
1338     TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1339                     nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1340
1341     info.fIcon = FALSE;
1342     info.xHotspot = xHotSpot;
1343     info.yHotspot = yHotSpot;
1344     info.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpANDbits );
1345     info.hbmColor = CreateBitmap( nWidth, nHeight, 1, 1, lpXORbits );
1346     hCursor = CreateIconIndirect( &info );
1347     DeleteObject( info.hbmMask );
1348     DeleteObject( info.hbmColor );
1349     return hCursor;
1350 }
1351
1352
1353 /***********************************************************************
1354  *              CreateIcon (USER32.@)
1355  *
1356  *  Creates an icon based on the specified bitmaps. The bitmaps must be
1357  *  provided in a device dependent format and will be resized to
1358  *  (SM_CXICON,SM_CYICON) and depth converted to match the screen's color
1359  *  depth. The provided bitmaps must be top-down bitmaps.
1360  *  Although Windows does not support 15bpp(*) this API must support it
1361  *  for Winelib applications.
1362  *
1363  *  (*) Windows does not support 15bpp but it supports the 555 RGB 16bpp
1364  *      format!
1365  *
1366  * RETURNS
1367  *  Success: handle to an icon
1368  *  Failure: NULL
1369  *
1370  * FIXME: Do we need to resize the bitmaps?
1371  */
1372 HICON WINAPI CreateIcon(
1373     HINSTANCE hInstance,  /* [in] the application's hInstance */
1374     INT       nWidth,     /* [in] the width of the provided bitmaps */
1375     INT       nHeight,    /* [in] the height of the provided bitmaps */
1376     BYTE      bPlanes,    /* [in] the number of planes in the provided bitmaps */
1377     BYTE      bBitsPixel, /* [in] the number of bits per pixel of the lpXORbits bitmap */
1378     LPCVOID   lpANDbits,  /* [in] a monochrome bitmap representing the icon's mask */
1379     LPCVOID   lpXORbits)  /* [in] the icon's 'color' bitmap */
1380 {
1381     ICONINFO iinfo;
1382     HICON hIcon;
1383
1384     TRACE_(icon)("%dx%d, planes %d, bpp %d, xor %p, and %p\n",
1385                  nWidth, nHeight, bPlanes, bBitsPixel, lpXORbits, lpANDbits);
1386
1387     iinfo.fIcon = TRUE;
1388     iinfo.xHotspot = nWidth / 2;
1389     iinfo.yHotspot = nHeight / 2;
1390     iinfo.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpANDbits );
1391     iinfo.hbmColor = CreateBitmap( nWidth, nHeight, bPlanes, bBitsPixel, lpXORbits );
1392
1393     hIcon = CreateIconIndirect( &iinfo );
1394
1395     DeleteObject( iinfo.hbmMask );
1396     DeleteObject( iinfo.hbmColor );
1397
1398     return hIcon;
1399 }
1400
1401
1402 /***********************************************************************
1403  *              CopyIcon (USER32.@)
1404  */
1405 HICON WINAPI CopyIcon( HICON hIcon )
1406 {
1407     struct cursoricon_object *ptrOld, *ptrNew;
1408     HICON hNew;
1409
1410     if (!(ptrOld = get_icon_ptr( hIcon )))
1411     {
1412         SetLastError( ERROR_INVALID_CURSOR_HANDLE );
1413         return 0;
1414     }
1415     if ((hNew = alloc_icon_handle(1)))
1416     {
1417         ptrNew = get_icon_ptr( hNew );
1418         ptrNew->is_icon = ptrOld->is_icon;
1419         ptrNew->width   = ptrOld->width;
1420         ptrNew->height  = ptrOld->height;
1421         ptrNew->hotspot = ptrOld->hotspot;
1422         ptrNew->frames[0].mask  = copy_bitmap( ptrOld->frames[0].mask );
1423         ptrNew->frames[0].color = copy_bitmap( ptrOld->frames[0].color );
1424         ptrNew->frames[0].alpha = copy_bitmap( ptrOld->frames[0].alpha );
1425         release_icon_ptr( hNew, ptrNew );
1426     }
1427     release_icon_ptr( hIcon, ptrOld );
1428     if (hNew) USER_Driver->pCreateCursorIcon( hNew );
1429     return hNew;
1430 }
1431
1432
1433 /***********************************************************************
1434  *              DestroyIcon (USER32.@)
1435  */
1436 BOOL WINAPI DestroyIcon( HICON hIcon )
1437 {
1438     BOOL ret = FALSE;
1439     struct cursoricon_object *obj = get_icon_ptr( hIcon );
1440
1441     TRACE_(icon)("%p\n", hIcon );
1442
1443     if (obj)
1444     {
1445         BOOL shared = (obj->rsrc != NULL);
1446         release_icon_ptr( hIcon, obj );
1447         ret = (GetCursor() != hIcon);
1448         if (!shared) free_icon_handle( hIcon );
1449     }
1450     return ret;
1451 }
1452
1453
1454 /***********************************************************************
1455  *              DestroyCursor (USER32.@)
1456  */
1457 BOOL WINAPI DestroyCursor( HCURSOR hCursor )
1458 {
1459     return DestroyIcon( hCursor );
1460 }
1461
1462 /***********************************************************************
1463  *              DrawIcon (USER32.@)
1464  */
1465 BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
1466 {
1467     return DrawIconEx( hdc, x, y, hIcon, 0, 0, 0, 0, DI_NORMAL | DI_COMPAT | DI_DEFAULTSIZE );
1468 }
1469
1470 /***********************************************************************
1471  *              SetCursor (USER32.@)
1472  *
1473  * Set the cursor shape.
1474  *
1475  * RETURNS
1476  *      A handle to the previous cursor shape.
1477  */
1478 HCURSOR WINAPI DECLSPEC_HOTPATCH SetCursor( HCURSOR hCursor /* [in] Handle of cursor to show */ )
1479 {
1480     struct cursoricon_object *obj;
1481     HCURSOR hOldCursor;
1482     int show_count;
1483     BOOL ret;
1484
1485     TRACE("%p\n", hCursor);
1486
1487     SERVER_START_REQ( set_cursor )
1488     {
1489         req->flags = SET_CURSOR_HANDLE;
1490         req->handle = wine_server_user_handle( hCursor );
1491         if ((ret = !wine_server_call_err( req )))
1492         {
1493             hOldCursor = wine_server_ptr_handle( reply->prev_handle );
1494             show_count = reply->prev_count;
1495         }
1496     }
1497     SERVER_END_REQ;
1498
1499     if (!ret) return 0;
1500
1501     /* Change the cursor shape only if it is visible */
1502     if (show_count >= 0 && hOldCursor != hCursor) USER_Driver->pSetCursor( hCursor );
1503
1504     if (!(obj = get_icon_ptr( hOldCursor ))) return 0;
1505     release_icon_ptr( hOldCursor, obj );
1506     return hOldCursor;
1507 }
1508
1509 /***********************************************************************
1510  *              ShowCursor (USER32.@)
1511  */
1512 INT WINAPI DECLSPEC_HOTPATCH ShowCursor( BOOL bShow )
1513 {
1514     HCURSOR cursor;
1515     int increment = bShow ? 1 : -1;
1516     int count;
1517
1518     SERVER_START_REQ( set_cursor )
1519     {
1520         req->flags = SET_CURSOR_COUNT;
1521         req->show_count = increment;
1522         wine_server_call( req );
1523         cursor = wine_server_ptr_handle( reply->prev_handle );
1524         count = reply->prev_count + increment;
1525     }
1526     SERVER_END_REQ;
1527
1528     TRACE("%d, count=%d\n", bShow, count );
1529
1530     if (bShow && !count) USER_Driver->pSetCursor( cursor );
1531     else if (!bShow && count == -1) USER_Driver->pSetCursor( 0 );
1532
1533     return count;
1534 }
1535
1536 /***********************************************************************
1537  *              GetCursor (USER32.@)
1538  */
1539 HCURSOR WINAPI GetCursor(void)
1540 {
1541     HCURSOR ret;
1542
1543     SERVER_START_REQ( set_cursor )
1544     {
1545         req->flags = 0;
1546         wine_server_call( req );
1547         ret = wine_server_ptr_handle( reply->prev_handle );
1548     }
1549     SERVER_END_REQ;
1550     return ret;
1551 }
1552
1553
1554 /***********************************************************************
1555  *              ClipCursor (USER32.@)
1556  */
1557 BOOL WINAPI DECLSPEC_HOTPATCH ClipCursor( const RECT *rect )
1558 {
1559     BOOL ret;
1560     RECT new_rect;
1561
1562     TRACE( "Clipping to %s\n", wine_dbgstr_rect(rect) );
1563
1564     SERVER_START_REQ( set_cursor )
1565     {
1566         req->flags = SET_CURSOR_CLIP;
1567         if (rect)
1568         {
1569             req->clip.left   = rect->left;
1570             req->clip.top    = rect->top;
1571             req->clip.right  = rect->right;
1572             req->clip.bottom = rect->bottom;
1573         }
1574         if ((ret = !wine_server_call( req )))
1575         {
1576             new_rect.left   = reply->new_clip.left;
1577             new_rect.top    = reply->new_clip.top;
1578             new_rect.right  = reply->new_clip.right;
1579             new_rect.bottom = reply->new_clip.bottom;
1580         }
1581     }
1582     SERVER_END_REQ;
1583     if (ret) USER_Driver->pClipCursor( &new_rect );
1584     return ret;
1585 }
1586
1587
1588 /***********************************************************************
1589  *              GetClipCursor (USER32.@)
1590  */
1591 BOOL WINAPI DECLSPEC_HOTPATCH GetClipCursor( RECT *rect )
1592 {
1593     BOOL ret;
1594
1595     if (!rect) return FALSE;
1596
1597     SERVER_START_REQ( set_cursor )
1598     {
1599         req->flags = 0;
1600         if ((ret = !wine_server_call( req )))
1601         {
1602             rect->left   = reply->new_clip.left;
1603             rect->top    = reply->new_clip.top;
1604             rect->right  = reply->new_clip.right;
1605             rect->bottom = reply->new_clip.bottom;
1606         }
1607     }
1608     SERVER_END_REQ;
1609     return ret;
1610 }
1611
1612
1613 /***********************************************************************
1614  *              SetSystemCursor (USER32.@)
1615  */
1616 BOOL WINAPI SetSystemCursor(HCURSOR hcur, DWORD id)
1617 {
1618     FIXME("(%p,%08x),stub!\n",  hcur, id);
1619     return TRUE;
1620 }
1621
1622
1623 /**********************************************************************
1624  *              LookupIconIdFromDirectoryEx (USER32.@)
1625  */
1626 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE xdir, BOOL bIcon,
1627              INT width, INT height, UINT cFlag )
1628 {
1629     const CURSORICONDIR *dir = (const CURSORICONDIR*)xdir;
1630     UINT retVal = 0;
1631     if( dir && !dir->idReserved && (dir->idType & 3) )
1632     {
1633         const CURSORICONDIRENTRY* entry;
1634
1635         const HDC hdc = GetDC(0);
1636         const int depth = (cFlag & LR_MONOCHROME) ?
1637             1 : GetDeviceCaps(hdc, BITSPIXEL);
1638         ReleaseDC(0, hdc);
1639
1640         if( bIcon )
1641             entry = CURSORICON_FindBestIconRes( dir, width, height, depth, LR_DEFAULTSIZE );
1642         else
1643             entry = CURSORICON_FindBestCursorRes( dir, width, height, depth, LR_DEFAULTSIZE );
1644
1645         if( entry ) retVal = entry->wResId;
1646     }
1647     else WARN_(cursor)("invalid resource directory\n");
1648     return retVal;
1649 }
1650
1651 /**********************************************************************
1652  *              LookupIconIdFromDirectory (USER32.@)
1653  */
1654 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1655 {
1656     return LookupIconIdFromDirectoryEx( dir, bIcon, 0, 0, bIcon ? 0 : LR_MONOCHROME );
1657 }
1658
1659 /***********************************************************************
1660  *              LoadCursorW (USER32.@)
1661  */
1662 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
1663 {
1664     TRACE("%p, %s\n", hInstance, debugstr_w(name));
1665
1666     return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0,
1667                        LR_SHARED | LR_DEFAULTSIZE );
1668 }
1669
1670 /***********************************************************************
1671  *              LoadCursorA (USER32.@)
1672  */
1673 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
1674 {
1675     TRACE("%p, %s\n", hInstance, debugstr_a(name));
1676
1677     return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0,
1678                        LR_SHARED | LR_DEFAULTSIZE );
1679 }
1680
1681 /***********************************************************************
1682  *              LoadCursorFromFileW (USER32.@)
1683  */
1684 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
1685 {
1686     TRACE("%s\n", debugstr_w(name));
1687
1688     return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0,
1689                        LR_LOADFROMFILE | LR_DEFAULTSIZE );
1690 }
1691
1692 /***********************************************************************
1693  *              LoadCursorFromFileA (USER32.@)
1694  */
1695 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
1696 {
1697     TRACE("%s\n", debugstr_a(name));
1698
1699     return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0,
1700                        LR_LOADFROMFILE | LR_DEFAULTSIZE );
1701 }
1702
1703 /***********************************************************************
1704  *              LoadIconW (USER32.@)
1705  */
1706 HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
1707 {
1708     TRACE("%p, %s\n", hInstance, debugstr_w(name));
1709
1710     return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0,
1711                        LR_SHARED | LR_DEFAULTSIZE );
1712 }
1713
1714 /***********************************************************************
1715  *              LoadIconA (USER32.@)
1716  */
1717 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
1718 {
1719     TRACE("%p, %s\n", hInstance, debugstr_a(name));
1720
1721     return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0,
1722                        LR_SHARED | LR_DEFAULTSIZE );
1723 }
1724
1725 /**********************************************************************
1726  *              GetCursorFrameInfo (USER32.@)
1727  */
1728 HCURSOR WINAPI GetCursorFrameInfo(HCURSOR hCursor, DWORD unk1, DWORD istep, DWORD *rate_jiffies, DWORD *num_steps)
1729 {
1730     struct cursoricon_object *ptr;
1731     HCURSOR ret = 0;
1732
1733     if (rate_jiffies == NULL || num_steps == NULL) return 0;
1734
1735     if (!(ptr = get_icon_ptr( hCursor ))) return 0;
1736
1737     FIXME("semi-stub! %p => %d %d %p %p\n", hCursor, unk1, istep, rate_jiffies, num_steps);
1738
1739     /* Important Note: Sequences are not currently supported, so this implementation
1740      * will not properly handle all cases. */
1741     if (istep < ptr->num_steps || ptr->num_frames == 1)
1742     {
1743         ret = hCursor;
1744         if (ptr->num_frames == 1)
1745         {
1746             *rate_jiffies = 0;
1747             *num_steps = 1;
1748         }
1749         else
1750         {
1751             if (ptr->num_steps == 1)
1752                 *num_steps = ~0;
1753             else
1754                 *num_steps = ptr->num_steps;
1755             *rate_jiffies = ptr->delay;
1756         }
1757     }
1758
1759     release_icon_ptr( hCursor, ptr );
1760
1761     return ret;
1762 }
1763
1764 /**********************************************************************
1765  *              GetIconInfo (USER32.@)
1766  */
1767 BOOL WINAPI GetIconInfo(HICON hIcon, PICONINFO iconinfo)
1768 {
1769     ICONINFOEXW infoW;
1770
1771     infoW.cbSize = sizeof(infoW);
1772     if (!GetIconInfoExW( hIcon, &infoW )) return FALSE;
1773     iconinfo->fIcon    = infoW.fIcon;
1774     iconinfo->xHotspot = infoW.xHotspot;
1775     iconinfo->yHotspot = infoW.yHotspot;
1776     iconinfo->hbmColor = infoW.hbmColor;
1777     iconinfo->hbmMask  = infoW.hbmMask;
1778     return TRUE;
1779 }
1780
1781 /**********************************************************************
1782  *              GetIconInfoExA (USER32.@)
1783  */
1784 BOOL WINAPI GetIconInfoExA( HICON icon, ICONINFOEXA *info )
1785 {
1786     ICONINFOEXW infoW;
1787
1788     if (info->cbSize != sizeof(*info))
1789     {
1790         SetLastError( ERROR_INVALID_PARAMETER );
1791         return FALSE;
1792     }
1793     infoW.cbSize = sizeof(infoW);
1794     if (!GetIconInfoExW( icon, &infoW )) return FALSE;
1795     info->fIcon    = infoW.fIcon;
1796     info->xHotspot = infoW.xHotspot;
1797     info->yHotspot = infoW.yHotspot;
1798     info->hbmColor = infoW.hbmColor;
1799     info->hbmMask  = infoW.hbmMask;
1800     info->wResID   = infoW.wResID;
1801     WideCharToMultiByte( CP_ACP, 0, infoW.szModName, -1, info->szModName, MAX_PATH, NULL, NULL );
1802     WideCharToMultiByte( CP_ACP, 0, infoW.szResName, -1, info->szResName, MAX_PATH, NULL, NULL );
1803     return TRUE;
1804 }
1805
1806 /**********************************************************************
1807  *              GetIconInfoExW (USER32.@)
1808  */
1809 BOOL WINAPI GetIconInfoExW( HICON icon, ICONINFOEXW *info )
1810 {
1811     struct cursoricon_object *ptr;
1812     HMODULE module;
1813     BOOL ret = TRUE;
1814
1815     if (info->cbSize != sizeof(*info))
1816     {
1817         SetLastError( ERROR_INVALID_PARAMETER );
1818         return FALSE;
1819     }
1820     if (!(ptr = get_icon_ptr( icon )))
1821     {
1822         SetLastError( ERROR_INVALID_CURSOR_HANDLE );
1823         return FALSE;
1824     }
1825
1826     TRACE("%p => %dx%d\n", icon, ptr->width, ptr->height);
1827
1828     info->fIcon        = ptr->is_icon;
1829     info->xHotspot     = ptr->hotspot.x;
1830     info->yHotspot     = ptr->hotspot.y;
1831     info->hbmColor     = copy_bitmap( ptr->frames[0].color );
1832     info->hbmMask      = copy_bitmap( ptr->frames[0].mask );
1833     info->wResID       = 0;
1834     info->szModName[0] = 0;
1835     info->szResName[0] = 0;
1836     if (ptr->module)
1837     {
1838         if (IS_INTRESOURCE( ptr->resname )) info->wResID = LOWORD( ptr->resname );
1839         else lstrcpynW( info->szResName, ptr->resname, MAX_PATH );
1840     }
1841     if (!info->hbmMask || (!info->hbmColor && ptr->frames[0].color))
1842     {
1843         DeleteObject( info->hbmMask );
1844         DeleteObject( info->hbmColor );
1845         ret = FALSE;
1846     }
1847     module = ptr->module;
1848     release_icon_ptr( icon, ptr );
1849     if (ret && module) GetModuleFileNameW( module, info->szModName, MAX_PATH );
1850     return ret;
1851 }
1852
1853 /* copy an icon bitmap, even when it can't be selected into a DC */
1854 /* helper for CreateIconIndirect */
1855 static void stretch_blt_icon( HDC hdc_dst, int dst_x, int dst_y, int dst_width, int dst_height,
1856                               HBITMAP src, int width, int height )
1857 {
1858     HDC hdc = CreateCompatibleDC( 0 );
1859
1860     if (!SelectObject( hdc, src ))  /* do it the hard way */
1861     {
1862         BITMAPINFO *info;
1863         void *bits;
1864
1865         if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) return;
1866         info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1867         info->bmiHeader.biWidth = width;
1868         info->bmiHeader.biHeight = height;
1869         info->bmiHeader.biPlanes = GetDeviceCaps( hdc_dst, PLANES );
1870         info->bmiHeader.biBitCount = GetDeviceCaps( hdc_dst, BITSPIXEL );
1871         info->bmiHeader.biCompression = BI_RGB;
1872         info->bmiHeader.biSizeImage = height * get_dib_width_bytes( width, info->bmiHeader.biBitCount );
1873         info->bmiHeader.biXPelsPerMeter = 0;
1874         info->bmiHeader.biYPelsPerMeter = 0;
1875         info->bmiHeader.biClrUsed = 0;
1876         info->bmiHeader.biClrImportant = 0;
1877         bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage );
1878         if (bits && GetDIBits( hdc, src, 0, height, bits, info, DIB_RGB_COLORS ))
1879             StretchDIBits( hdc_dst, dst_x, dst_y, dst_width, dst_height,
1880                            0, 0, width, height, bits, info, DIB_RGB_COLORS, SRCCOPY );
1881
1882         HeapFree( GetProcessHeap(), 0, bits );
1883         HeapFree( GetProcessHeap(), 0, info );
1884     }
1885     else StretchBlt( hdc_dst, dst_x, dst_y, dst_width, dst_height, hdc, 0, 0, width, height, SRCCOPY );
1886
1887     DeleteDC( hdc );
1888 }
1889
1890 /**********************************************************************
1891  *              CreateIconIndirect (USER32.@)
1892  */
1893 HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
1894 {
1895     BITMAP bmpXor, bmpAnd;
1896     HICON hObj;
1897     HBITMAP color = 0, mask;
1898     int width, height;
1899     HDC hdc;
1900
1901     TRACE("color %p, mask %p, hotspot %ux%u, fIcon %d\n",
1902            iconinfo->hbmColor, iconinfo->hbmMask,
1903            iconinfo->xHotspot, iconinfo->yHotspot, iconinfo->fIcon);
1904
1905     if (!iconinfo->hbmMask) return 0;
1906
1907     GetObjectW( iconinfo->hbmMask, sizeof(bmpAnd), &bmpAnd );
1908     TRACE("mask: width %d, height %d, width bytes %d, planes %u, bpp %u\n",
1909            bmpAnd.bmWidth, bmpAnd.bmHeight, bmpAnd.bmWidthBytes,
1910            bmpAnd.bmPlanes, bmpAnd.bmBitsPixel);
1911
1912     if (iconinfo->hbmColor)
1913     {
1914         GetObjectW( iconinfo->hbmColor, sizeof(bmpXor), &bmpXor );
1915         TRACE("color: width %d, height %d, width bytes %d, planes %u, bpp %u\n",
1916                bmpXor.bmWidth, bmpXor.bmHeight, bmpXor.bmWidthBytes,
1917                bmpXor.bmPlanes, bmpXor.bmBitsPixel);
1918
1919         width = bmpXor.bmWidth;
1920         height = bmpXor.bmHeight;
1921         if (bmpXor.bmPlanes * bmpXor.bmBitsPixel != 1)
1922         {
1923             color = CreateCompatibleBitmap( screen_dc, width, height );
1924             mask = CreateBitmap( width, height, 1, 1, NULL );
1925         }
1926         else mask = CreateBitmap( width, height * 2, 1, 1, NULL );
1927     }
1928     else
1929     {
1930         width = bmpAnd.bmWidth;
1931         height = bmpAnd.bmHeight;
1932         mask = CreateBitmap( width, height, 1, 1, NULL );
1933     }
1934
1935     hdc = CreateCompatibleDC( 0 );
1936     SelectObject( hdc, mask );
1937     stretch_blt_icon( hdc, 0, 0, width, height, iconinfo->hbmMask, bmpAnd.bmWidth, bmpAnd.bmHeight );
1938
1939     if (color)
1940     {
1941         SelectObject( hdc, color );
1942         stretch_blt_icon( hdc, 0, 0, width, height, iconinfo->hbmColor, width, height );
1943     }
1944     else if (iconinfo->hbmColor)
1945     {
1946         stretch_blt_icon( hdc, 0, height, width, height, iconinfo->hbmColor, width, height );
1947     }
1948     else height /= 2;
1949
1950     DeleteDC( hdc );
1951
1952     hObj = alloc_icon_handle(1);
1953     if (hObj)
1954     {
1955         struct cursoricon_object *info = get_icon_ptr( hObj );
1956
1957         info->is_icon = iconinfo->fIcon;
1958         info->width   = width;
1959         info->height  = height;
1960         info->frames[0].color = color;
1961         info->frames[0].mask  = mask;
1962         info->frames[0].alpha = create_alpha_bitmap( iconinfo->hbmColor, mask, NULL, NULL );
1963         if (info->is_icon)
1964         {
1965             info->hotspot.x = width / 2;
1966             info->hotspot.y = height / 2;
1967         }
1968         else
1969         {
1970             info->hotspot.x = iconinfo->xHotspot;
1971             info->hotspot.y = iconinfo->yHotspot;
1972         }
1973
1974         release_icon_ptr( hObj, info );
1975         USER_Driver->pCreateCursorIcon( hObj );
1976     }
1977     return hObj;
1978 }
1979
1980 /******************************************************************************
1981  *              DrawIconEx (USER32.@) Draws an icon or cursor on device context
1982  *
1983  * NOTES
1984  *    Why is this using SM_CXICON instead of SM_CXCURSOR?
1985  *
1986  * PARAMS
1987  *    hdc     [I] Handle to device context
1988  *    x0      [I] X coordinate of upper left corner
1989  *    y0      [I] Y coordinate of upper left corner
1990  *    hIcon   [I] Handle to icon to draw
1991  *    cxWidth [I] Width of icon
1992  *    cyWidth [I] Height of icon
1993  *    istep   [I] Index of frame in animated cursor
1994  *    hbr     [I] Handle to background brush
1995  *    flags   [I] Icon-drawing flags
1996  *
1997  * RETURNS
1998  *    Success: TRUE
1999  *    Failure: FALSE
2000  */
2001 BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
2002                             INT cxWidth, INT cyWidth, UINT istep,
2003                             HBRUSH hbr, UINT flags )
2004 {
2005     struct cursoricon_object *ptr;
2006     HDC hdc_dest, hMemDC;
2007     BOOL result = FALSE, DoOffscreen;
2008     HBITMAP hB_off = 0;
2009     COLORREF oldFg, oldBg;
2010     INT x, y, nStretchMode;
2011
2012     TRACE_(icon)("(hdc=%p,pos=%d.%d,hicon=%p,extend=%d.%d,istep=%d,br=%p,flags=0x%08x)\n",
2013                  hdc,x0,y0,hIcon,cxWidth,cyWidth,istep,hbr,flags );
2014
2015     if (!(ptr = get_icon_ptr( hIcon ))) return FALSE;
2016     if (istep >= ptr->num_steps)
2017     {
2018         TRACE_(icon)("Stepped past end of animated frames=%d\n", istep);
2019         release_icon_ptr( hIcon, ptr );
2020         return FALSE;
2021     }
2022     if (!(hMemDC = CreateCompatibleDC( hdc )))
2023     {
2024         release_icon_ptr( hIcon, ptr );
2025         return FALSE;
2026     }
2027
2028     if (flags & DI_NOMIRROR)
2029         FIXME_(icon)("Ignoring flag DI_NOMIRROR\n");
2030
2031     /* Calculate the size of the destination image.  */
2032     if (cxWidth == 0)
2033     {
2034         if (flags & DI_DEFAULTSIZE)
2035             cxWidth = GetSystemMetrics (SM_CXICON);
2036         else
2037             cxWidth = ptr->width;
2038     }
2039     if (cyWidth == 0)
2040     {
2041         if (flags & DI_DEFAULTSIZE)
2042             cyWidth = GetSystemMetrics (SM_CYICON);
2043         else
2044             cyWidth = ptr->height;
2045     }
2046
2047     DoOffscreen = (GetObjectType( hbr ) == OBJ_BRUSH);
2048
2049     if (DoOffscreen) {
2050         RECT r;
2051
2052         r.left = 0;
2053         r.top = 0;
2054         r.right = cxWidth;
2055         r.bottom = cxWidth;
2056
2057         if (!(hdc_dest = CreateCompatibleDC(hdc))) goto failed;
2058         if (!(hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth)))
2059         {
2060             DeleteDC( hdc_dest );
2061             goto failed;
2062         }
2063         SelectObject(hdc_dest, hB_off);
2064         FillRect(hdc_dest, &r, hbr);
2065         x = y = 0;
2066     }
2067     else
2068     {
2069         hdc_dest = hdc;
2070         x = x0;
2071         y = y0;
2072     }
2073
2074     nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
2075
2076     oldFg = SetTextColor( hdc, RGB(0,0,0) );
2077     oldBg = SetBkColor( hdc, RGB(255,255,255) );
2078
2079     if (ptr->frames[istep].alpha && (flags & DI_IMAGE))
2080     {
2081         BOOL is_mono = FALSE;
2082
2083         if (GetObjectType( hdc_dest ) == OBJ_MEMDC)
2084         {
2085             BITMAP bm;
2086             HBITMAP bmp = GetCurrentObject( hdc_dest, OBJ_BITMAP );
2087             is_mono = GetObjectW( bmp, sizeof(bm), &bm ) && bm.bmBitsPixel == 1;
2088         }
2089         if (!is_mono)
2090         {
2091             BLENDFUNCTION pixelblend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
2092             SelectObject( hMemDC, ptr->frames[istep].alpha );
2093             if (GdiAlphaBlend( hdc_dest, x, y, cxWidth, cyWidth, hMemDC,
2094                                0, 0, ptr->width, ptr->height, pixelblend )) goto done;
2095         }
2096     }
2097
2098     if (flags & DI_MASK)
2099     {
2100         SelectObject( hMemDC, ptr->frames[istep].mask );
2101         StretchBlt( hdc_dest, x, y, cxWidth, cyWidth,
2102                     hMemDC, 0, 0, ptr->width, ptr->height, SRCAND );
2103     }
2104
2105     if (flags & DI_IMAGE)
2106     {
2107         if (ptr->frames[istep].color)
2108         {
2109             DWORD rop = (flags & DI_MASK) ? SRCINVERT : SRCCOPY;
2110             SelectObject( hMemDC, ptr->frames[istep].color );
2111             StretchBlt( hdc_dest, x, y, cxWidth, cyWidth,
2112                         hMemDC, 0, 0, ptr->width, ptr->height, rop );
2113         }
2114         else
2115         {
2116             DWORD rop = (flags & DI_MASK) ? SRCINVERT : SRCCOPY;
2117             SelectObject( hMemDC, ptr->frames[istep].mask );
2118             StretchBlt( hdc_dest, x, y, cxWidth, cyWidth,
2119                         hMemDC, 0, ptr->height, ptr->width, ptr->height, rop );
2120         }
2121     }
2122
2123 done:
2124     if (DoOffscreen) BitBlt( hdc, x0, y0, cxWidth, cyWidth, hdc_dest, 0, 0, SRCCOPY );
2125
2126     SetTextColor( hdc, oldFg );
2127     SetBkColor( hdc, oldBg );
2128     SetStretchBltMode (hdc, nStretchMode);
2129     result = TRUE;
2130     if (hdc_dest != hdc) DeleteDC( hdc_dest );
2131     if (hB_off) DeleteObject(hB_off);
2132 failed:
2133     DeleteDC( hMemDC );
2134     release_icon_ptr( hIcon, ptr );
2135     return result;
2136 }
2137
2138 /***********************************************************************
2139  *           DIB_FixColorsToLoadflags
2140  *
2141  * Change color table entries when LR_LOADTRANSPARENT or LR_LOADMAP3DCOLORS
2142  * are in loadflags
2143  */
2144 static void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags, BYTE pix)
2145 {
2146     int colors;
2147     COLORREF c_W, c_S, c_F, c_L, c_C;
2148     int incr,i;
2149     RGBQUAD *ptr;
2150     int bitmap_type;
2151     LONG width;
2152     LONG height;
2153     WORD bpp;
2154     DWORD compr;
2155
2156     if (((bitmap_type = DIB_GetBitmapInfo((BITMAPINFOHEADER*) bmi, &width, &height, &bpp, &compr)) == -1))
2157     {
2158         WARN_(resource)("Invalid bitmap\n");
2159         return;
2160     }
2161
2162     if (bpp > 8) return;
2163
2164     if (bitmap_type == 0) /* BITMAPCOREHEADER */
2165     {
2166         incr = 3;
2167         colors = 1 << bpp;
2168     }
2169     else
2170     {
2171         incr = 4;
2172         colors = bmi->bmiHeader.biClrUsed;
2173         if (colors > 256) colors = 256;
2174         if (!colors && (bpp <= 8)) colors = 1 << bpp;
2175     }
2176
2177     c_W = GetSysColor(COLOR_WINDOW);
2178     c_S = GetSysColor(COLOR_3DSHADOW);
2179     c_F = GetSysColor(COLOR_3DFACE);
2180     c_L = GetSysColor(COLOR_3DLIGHT);
2181
2182     if (loadflags & LR_LOADTRANSPARENT) {
2183         switch (bpp) {
2184         case 1: pix = pix >> 7; break;
2185         case 4: pix = pix >> 4; break;
2186         case 8: break;
2187         default:
2188             WARN_(resource)("(%d): Unsupported depth\n", bpp);
2189             return;
2190         }
2191         if (pix >= colors) {
2192             WARN_(resource)("pixel has color index greater than biClrUsed!\n");
2193             return;
2194         }
2195         if (loadflags & LR_LOADMAP3DCOLORS) c_W = c_F;
2196         ptr = (RGBQUAD*)((char*)bmi->bmiColors+pix*incr);
2197         ptr->rgbBlue = GetBValue(c_W);
2198         ptr->rgbGreen = GetGValue(c_W);
2199         ptr->rgbRed = GetRValue(c_W);
2200     }
2201     if (loadflags & LR_LOADMAP3DCOLORS)
2202         for (i=0; i<colors; i++) {
2203             ptr = (RGBQUAD*)((char*)bmi->bmiColors+i*incr);
2204             c_C = RGB(ptr->rgbRed, ptr->rgbGreen, ptr->rgbBlue);
2205             if (c_C == RGB(128, 128, 128)) {
2206                 ptr->rgbRed = GetRValue(c_S);
2207                 ptr->rgbGreen = GetGValue(c_S);
2208                 ptr->rgbBlue = GetBValue(c_S);
2209             } else if (c_C == RGB(192, 192, 192)) {
2210                 ptr->rgbRed = GetRValue(c_F);
2211                 ptr->rgbGreen = GetGValue(c_F);
2212                 ptr->rgbBlue = GetBValue(c_F);
2213             } else if (c_C == RGB(223, 223, 223)) {
2214                 ptr->rgbRed = GetRValue(c_L);
2215                 ptr->rgbGreen = GetGValue(c_L);
2216                 ptr->rgbBlue = GetBValue(c_L);
2217             }
2218         }
2219 }
2220
2221
2222 /**********************************************************************
2223  *       BITMAP_Load
2224  */
2225 static HBITMAP BITMAP_Load( HINSTANCE instance, LPCWSTR name,
2226                             INT desiredx, INT desiredy, UINT loadflags )
2227 {
2228     HBITMAP hbitmap = 0, orig_bm;
2229     HRSRC hRsrc;
2230     HGLOBAL handle;
2231     char *ptr = NULL;
2232     BITMAPINFO *info, *fix_info = NULL, *scaled_info = NULL;
2233     int size;
2234     BYTE pix;
2235     char *bits;
2236     LONG width, height, new_width, new_height;
2237     WORD bpp_dummy;
2238     DWORD compr_dummy, offbits = 0;
2239     INT bm_type;
2240     HDC screen_mem_dc = NULL;
2241
2242     if (!(loadflags & LR_LOADFROMFILE))
2243     {
2244         if (!instance)
2245         {
2246             /* OEM bitmap: try to load the resource from user32.dll */
2247             instance = user32_module;
2248         }
2249
2250         if (!(hRsrc = FindResourceW( instance, name, (LPWSTR)RT_BITMAP ))) return 0;
2251         if (!(handle = LoadResource( instance, hRsrc ))) return 0;
2252
2253         if ((info = LockResource( handle )) == NULL) return 0;
2254     }
2255     else
2256     {
2257         BITMAPFILEHEADER * bmfh;
2258
2259         if (!(ptr = map_fileW( name, NULL ))) return 0;
2260         info = (BITMAPINFO *)(ptr + sizeof(BITMAPFILEHEADER));
2261         bmfh = (BITMAPFILEHEADER *)ptr;
2262         if (bmfh->bfType != 0x4d42 /* 'BM' */)
2263         {
2264             WARN("Invalid/unsupported bitmap format!\n");
2265             goto end;
2266         }
2267         if (bmfh->bfOffBits) offbits = bmfh->bfOffBits - sizeof(BITMAPFILEHEADER);
2268     }
2269
2270     bm_type = DIB_GetBitmapInfo( &info->bmiHeader, &width, &height,
2271                                  &bpp_dummy, &compr_dummy);
2272     if (bm_type == -1)
2273     {
2274         WARN("Invalid bitmap format!\n");
2275         goto end;
2276     }
2277
2278     size = bitmap_info_size(info, DIB_RGB_COLORS);
2279     fix_info = HeapAlloc(GetProcessHeap(), 0, size);
2280     scaled_info = HeapAlloc(GetProcessHeap(), 0, size);
2281
2282     if (!fix_info || !scaled_info) goto end;
2283     memcpy(fix_info, info, size);
2284
2285     pix = *((LPBYTE)info + size);
2286     DIB_FixColorsToLoadflags(fix_info, loadflags, pix);
2287
2288     memcpy(scaled_info, fix_info, size);
2289
2290     if(desiredx != 0)
2291         new_width = desiredx;
2292     else
2293         new_width = width;
2294
2295     if(desiredy != 0)
2296         new_height = height > 0 ? desiredy : -desiredy;
2297     else
2298         new_height = height;
2299
2300     if(bm_type == 0)
2301     {
2302         BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)&scaled_info->bmiHeader;
2303         core->bcWidth = new_width;
2304         core->bcHeight = new_height;
2305     }
2306     else
2307     {
2308         /* Some sanity checks for BITMAPINFO (not applicable to BITMAPCOREINFO) */
2309         if (info->bmiHeader.biHeight > 65535 || info->bmiHeader.biWidth > 65535) {
2310             WARN("Broken BitmapInfoHeader!\n");
2311             goto end;
2312         }
2313
2314         scaled_info->bmiHeader.biWidth = new_width;
2315         scaled_info->bmiHeader.biHeight = new_height;
2316     }
2317
2318     if (new_height < 0) new_height = -new_height;
2319
2320     if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
2321     if (!(screen_mem_dc = CreateCompatibleDC( screen_dc ))) goto end;
2322
2323     bits = (char *)info + (offbits ? offbits : size);
2324
2325     if (loadflags & LR_CREATEDIBSECTION)
2326     {
2327         scaled_info->bmiHeader.biCompression = 0; /* DIBSection can't be compressed */
2328         hbitmap = CreateDIBSection(screen_dc, scaled_info, DIB_RGB_COLORS, NULL, 0, 0);
2329     }
2330     else
2331     {
2332         if (is_dib_monochrome(fix_info))
2333             hbitmap = CreateBitmap(new_width, new_height, 1, 1, NULL);
2334         else
2335             hbitmap = CreateCompatibleBitmap(screen_dc, new_width, new_height);        
2336     }
2337
2338     orig_bm = SelectObject(screen_mem_dc, hbitmap);
2339     StretchDIBits(screen_mem_dc, 0, 0, new_width, new_height, 0, 0, width, height, bits, fix_info, DIB_RGB_COLORS, SRCCOPY);
2340     SelectObject(screen_mem_dc, orig_bm);
2341
2342 end:
2343     if (screen_mem_dc) DeleteDC(screen_mem_dc);
2344     HeapFree(GetProcessHeap(), 0, scaled_info);
2345     HeapFree(GetProcessHeap(), 0, fix_info);
2346     if (loadflags & LR_LOADFROMFILE) UnmapViewOfFile( ptr );
2347
2348     return hbitmap;
2349 }
2350
2351 /**********************************************************************
2352  *              LoadImageA (USER32.@)
2353  *
2354  * See LoadImageW.
2355  */
2356 HANDLE WINAPI LoadImageA( HINSTANCE hinst, LPCSTR name, UINT type,
2357                               INT desiredx, INT desiredy, UINT loadflags)
2358 {
2359     HANDLE res;
2360     LPWSTR u_name;
2361
2362     if (IS_INTRESOURCE(name))
2363         return LoadImageW(hinst, (LPCWSTR)name, type, desiredx, desiredy, loadflags);
2364
2365     __TRY {
2366         DWORD len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
2367         u_name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2368         MultiByteToWideChar( CP_ACP, 0, name, -1, u_name, len );
2369     }
2370     __EXCEPT_PAGE_FAULT {
2371         SetLastError( ERROR_INVALID_PARAMETER );
2372         return 0;
2373     }
2374     __ENDTRY
2375     res = LoadImageW(hinst, u_name, type, desiredx, desiredy, loadflags);
2376     HeapFree(GetProcessHeap(), 0, u_name);
2377     return res;
2378 }
2379
2380
2381 /******************************************************************************
2382  *              LoadImageW (USER32.@) Loads an icon, cursor, or bitmap
2383  *
2384  * PARAMS
2385  *    hinst     [I] Handle of instance that contains image
2386  *    name      [I] Name of image
2387  *    type      [I] Type of image
2388  *    desiredx  [I] Desired width
2389  *    desiredy  [I] Desired height
2390  *    loadflags [I] Load flags
2391  *
2392  * RETURNS
2393  *    Success: Handle to newly loaded image
2394  *    Failure: NULL
2395  *
2396  * FIXME: Implementation lacks some features, see LR_ defines in winuser.h
2397  */
2398 HANDLE WINAPI LoadImageW( HINSTANCE hinst, LPCWSTR name, UINT type,
2399                 INT desiredx, INT desiredy, UINT loadflags )
2400 {
2401     TRACE_(resource)("(%p,%s,%d,%d,%d,0x%08x)\n",
2402                      hinst,debugstr_w(name),type,desiredx,desiredy,loadflags);
2403
2404     if (loadflags & LR_LOADFROMFILE) loadflags &= ~LR_SHARED;
2405     switch (type) {
2406     case IMAGE_BITMAP:
2407         return BITMAP_Load( hinst, name, desiredx, desiredy, loadflags );
2408
2409     case IMAGE_ICON:
2410         if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
2411         if (screen_dc)
2412         {
2413             return CURSORICON_Load(hinst, name, desiredx, desiredy,
2414                                    GetDeviceCaps(screen_dc, BITSPIXEL),
2415                                    FALSE, loadflags);
2416         }
2417         break;
2418
2419     case IMAGE_CURSOR:
2420         return CURSORICON_Load(hinst, name, desiredx, desiredy,
2421                                1, TRUE, loadflags);
2422     }
2423     return 0;
2424 }
2425
2426 /******************************************************************************
2427  *              CopyImage (USER32.@) Creates new image and copies attributes to it
2428  *
2429  * PARAMS
2430  *    hnd      [I] Handle to image to copy
2431  *    type     [I] Type of image to copy
2432  *    desiredx [I] Desired width of new image
2433  *    desiredy [I] Desired height of new image
2434  *    flags    [I] Copy flags
2435  *
2436  * RETURNS
2437  *    Success: Handle to newly created image
2438  *    Failure: NULL
2439  *
2440  * BUGS
2441  *    Only Windows NT 4.0 supports the LR_COPYRETURNORG flag for bitmaps,
2442  *    all other versions (95/2000/XP have been tested) ignore it.
2443  *
2444  * NOTES
2445  *    If LR_CREATEDIBSECTION is absent, the copy will be monochrome for
2446  *    a monochrome source bitmap or if LR_MONOCHROME is present, otherwise
2447  *    the copy will have the same depth as the screen.
2448  *    The content of the image will only be copied if the bit depth of the
2449  *    original image is compatible with the bit depth of the screen, or
2450  *    if the source is a DIB section.
2451  *    The LR_MONOCHROME flag is ignored if LR_CREATEDIBSECTION is present.
2452  */
2453 HANDLE WINAPI CopyImage( HANDLE hnd, UINT type, INT desiredx,
2454                              INT desiredy, UINT flags )
2455 {
2456     TRACE("hnd=%p, type=%u, desiredx=%d, desiredy=%d, flags=%x\n",
2457           hnd, type, desiredx, desiredy, flags);
2458
2459     switch (type)
2460     {
2461         case IMAGE_BITMAP:
2462         {
2463             HBITMAP res = NULL;
2464             DIBSECTION ds;
2465             int objSize;
2466             BITMAPINFO * bi;
2467
2468             objSize = GetObjectW( hnd, sizeof(ds), &ds );
2469             if (!objSize) return 0;
2470             if ((desiredx < 0) || (desiredy < 0)) return 0;
2471
2472             if (flags & LR_COPYFROMRESOURCE)
2473             {
2474                 FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
2475             }
2476
2477             if (desiredx == 0) desiredx = ds.dsBm.bmWidth;
2478             if (desiredy == 0) desiredy = ds.dsBm.bmHeight;
2479
2480             /* Allocate memory for a BITMAPINFOHEADER structure and a
2481                color table. The maximum number of colors in a color table
2482                is 256 which corresponds to a bitmap with depth 8.
2483                Bitmaps with higher depths don't have color tables. */
2484             bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2485             if (!bi) return 0;
2486
2487             bi->bmiHeader.biSize        = sizeof(bi->bmiHeader);
2488             bi->bmiHeader.biPlanes      = ds.dsBm.bmPlanes;
2489             bi->bmiHeader.biBitCount    = ds.dsBm.bmBitsPixel;
2490             bi->bmiHeader.biCompression = BI_RGB;
2491
2492             if (flags & LR_CREATEDIBSECTION)
2493             {
2494                 /* Create a DIB section. LR_MONOCHROME is ignored */
2495                 void * bits;
2496                 HDC dc = CreateCompatibleDC(NULL);
2497
2498                 if (objSize == sizeof(DIBSECTION))
2499                 {
2500                     /* The source bitmap is a DIB.
2501                        Get its attributes to create an exact copy */
2502                     memcpy(bi, &ds.dsBmih, sizeof(BITMAPINFOHEADER));
2503                 }
2504
2505                 /* Get the color table or the color masks */
2506                 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
2507
2508                 bi->bmiHeader.biWidth  = desiredx;
2509                 bi->bmiHeader.biHeight = desiredy;
2510                 bi->bmiHeader.biSizeImage = 0;
2511
2512                 res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
2513                 DeleteDC(dc);
2514             }
2515             else
2516             {
2517                 /* Create a device-dependent bitmap */
2518
2519                 BOOL monochrome = (flags & LR_MONOCHROME);
2520
2521                 if (objSize == sizeof(DIBSECTION))
2522                 {
2523                     /* The source bitmap is a DIB section.
2524                        Get its attributes */
2525                     HDC dc = CreateCompatibleDC(NULL);
2526                     bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
2527                     bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
2528                     GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
2529                     DeleteDC(dc);
2530
2531                     if (!monochrome && ds.dsBm.bmBitsPixel == 1)
2532                     {
2533                         /* Look if the colors of the DIB are black and white */
2534
2535                         monochrome = 
2536                               (bi->bmiColors[0].rgbRed == 0xff
2537                             && bi->bmiColors[0].rgbGreen == 0xff
2538                             && bi->bmiColors[0].rgbBlue == 0xff
2539                             && bi->bmiColors[0].rgbReserved == 0
2540                             && bi->bmiColors[1].rgbRed == 0
2541                             && bi->bmiColors[1].rgbGreen == 0
2542                             && bi->bmiColors[1].rgbBlue == 0
2543                             && bi->bmiColors[1].rgbReserved == 0)
2544                             ||
2545                               (bi->bmiColors[0].rgbRed == 0
2546                             && bi->bmiColors[0].rgbGreen == 0
2547                             && bi->bmiColors[0].rgbBlue == 0
2548                             && bi->bmiColors[0].rgbReserved == 0
2549                             && bi->bmiColors[1].rgbRed == 0xff
2550                             && bi->bmiColors[1].rgbGreen == 0xff
2551                             && bi->bmiColors[1].rgbBlue == 0xff
2552                             && bi->bmiColors[1].rgbReserved == 0);
2553                     }
2554                 }
2555                 else if (!monochrome)
2556                 {
2557                     monochrome = ds.dsBm.bmBitsPixel == 1;
2558                 }
2559
2560                 if (monochrome)
2561                 {
2562                     res = CreateBitmap(desiredx, desiredy, 1, 1, NULL);
2563                 }
2564                 else
2565                 {
2566                     HDC screenDC = GetDC(NULL);
2567                     res = CreateCompatibleBitmap(screenDC, desiredx, desiredy);
2568                     ReleaseDC(NULL, screenDC);
2569                 }
2570             }
2571
2572             if (res)
2573             {
2574                 /* Only copy the bitmap if it's a DIB section or if it's
2575                    compatible to the screen */
2576                 BOOL copyContents;
2577
2578                 if (objSize == sizeof(DIBSECTION))
2579                 {
2580                     copyContents = TRUE;
2581                 }
2582                 else
2583                 {
2584                     HDC screenDC = GetDC(NULL);
2585                     int screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
2586                     ReleaseDC(NULL, screenDC);
2587
2588                     copyContents = (ds.dsBm.bmBitsPixel == 1 || ds.dsBm.bmBitsPixel == screen_depth);
2589                 }
2590
2591                 if (copyContents)
2592                 {
2593                     /* The source bitmap may already be selected in a device context,
2594                        use GetDIBits/StretchDIBits and not StretchBlt  */
2595
2596                     HDC dc;
2597                     void * bits;
2598
2599                     dc = CreateCompatibleDC(NULL);
2600
2601                     bi->bmiHeader.biWidth = ds.dsBm.bmWidth;
2602                     bi->bmiHeader.biHeight = ds.dsBm.bmHeight;
2603                     bi->bmiHeader.biSizeImage = 0;
2604                     bi->bmiHeader.biClrUsed = 0;
2605                     bi->bmiHeader.biClrImportant = 0;
2606
2607                     /* Fill in biSizeImage */
2608                     GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
2609                     bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bi->bmiHeader.biSizeImage);
2610
2611                     if (bits)
2612                     {
2613                         HBITMAP oldBmp;
2614
2615                         /* Get the image bits of the source bitmap */
2616                         GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS);
2617
2618                         /* Copy it to the destination bitmap */
2619                         oldBmp = SelectObject(dc, res);
2620                         StretchDIBits(dc, 0, 0, desiredx, desiredy,
2621                                       0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight,
2622                                       bits, bi, DIB_RGB_COLORS, SRCCOPY);
2623                         SelectObject(dc, oldBmp);
2624
2625                         HeapFree(GetProcessHeap(), 0, bits);
2626                     }
2627
2628                     DeleteDC(dc);
2629                 }
2630
2631                 if (flags & LR_COPYDELETEORG)
2632                 {
2633                     DeleteObject(hnd);
2634                 }
2635             }
2636             HeapFree(GetProcessHeap(), 0, bi);
2637             return res;
2638         }
2639         case IMAGE_ICON:
2640         case IMAGE_CURSOR:
2641         {
2642             struct cursoricon_object *icon;
2643             HICON res = 0;
2644             int depth = (flags & LR_MONOCHROME) ? 1 : GetDeviceCaps( screen_dc, BITSPIXEL );
2645
2646             if (flags & LR_DEFAULTSIZE)
2647             {
2648                 if (!desiredx) desiredx = GetSystemMetrics( type == IMAGE_ICON ? SM_CXICON : SM_CXCURSOR );
2649                 if (!desiredy) desiredy = GetSystemMetrics( type == IMAGE_ICON ? SM_CYICON : SM_CYCURSOR );
2650             }
2651
2652             if (!(icon = get_icon_ptr( hnd ))) return 0;
2653
2654             if (icon->rsrc && (flags & LR_COPYFROMRESOURCE))
2655                 res = CURSORICON_Load( icon->module, icon->resname, desiredx, desiredy, depth,
2656                                        type == IMAGE_CURSOR, flags );
2657             else
2658                 res = CopyIcon( hnd ); /* FIXME: change size if necessary */
2659             release_icon_ptr( hnd, icon );
2660
2661             if (res && (flags & LR_COPYDELETEORG)) DeleteObject( hnd );
2662             return res;
2663         }
2664     }
2665     return 0;
2666 }
2667
2668
2669 /******************************************************************************
2670  *              LoadBitmapW (USER32.@) Loads bitmap from the executable file
2671  *
2672  * RETURNS
2673  *    Success: Handle to specified bitmap
2674  *    Failure: NULL
2675  */
2676 HBITMAP WINAPI LoadBitmapW(
2677     HINSTANCE instance, /* [in] Handle to application instance */
2678     LPCWSTR name)         /* [in] Address of bitmap resource name */
2679 {
2680     return LoadImageW( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2681 }
2682
2683 /**********************************************************************
2684  *              LoadBitmapA (USER32.@)
2685  *
2686  * See LoadBitmapW.
2687  */
2688 HBITMAP WINAPI LoadBitmapA( HINSTANCE instance, LPCSTR name )
2689 {
2690     return LoadImageA( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2691 }