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