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