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