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