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