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