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