Const correctness fixes.
[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 /***********************************************************************
1560  *              SetSystemCursor (USER32.@)
1561  */
1562 BOOL WINAPI SetSystemCursor(HCURSOR hcur, DWORD id)
1563 {
1564     FIXME("(%p,%08lx),stub!\n",  hcur, id);
1565     return TRUE;
1566 }
1567
1568
1569 /**********************************************************************
1570  *              LookupIconIdFromDirectoryEx (USER.364)
1571  *
1572  * FIXME: exact parameter sizes
1573  */
1574 INT16 WINAPI LookupIconIdFromDirectoryEx16( LPBYTE dir, BOOL16 bIcon,
1575                                             INT16 width, INT16 height, UINT16 cFlag )
1576 {
1577     return LookupIconIdFromDirectoryEx( dir, bIcon, width, height, cFlag );
1578 }
1579
1580 /**********************************************************************
1581  *              LookupIconIdFromDirectoryEx (USER32.@)
1582  */
1583 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE xdir, BOOL bIcon,
1584              INT width, INT height, UINT cFlag )
1585 {
1586     CURSORICONDIR       *dir = (CURSORICONDIR*)xdir;
1587     UINT retVal = 0;
1588     if( dir && !dir->idReserved && (dir->idType & 3) )
1589     {
1590         CURSORICONDIRENTRY* entry;
1591         HDC hdc;
1592         UINT palEnts;
1593         int colors;
1594         hdc = GetDC(0);
1595         palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
1596         if (palEnts == 0)
1597             palEnts = 256;
1598         colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
1599
1600         ReleaseDC(0, hdc);
1601
1602         if( bIcon )
1603             entry = CURSORICON_FindBestIcon( dir, width, height, colors );
1604         else
1605             entry = CURSORICON_FindBestCursor( dir, width, height, 1);
1606
1607         if( entry ) retVal = entry->wResId;
1608     }
1609     else WARN_(cursor)("invalid resource directory\n");
1610     return retVal;
1611 }
1612
1613 /**********************************************************************
1614  *              LookupIconIdFromDirectory (USER.?)
1615  */
1616 INT16 WINAPI LookupIconIdFromDirectory16( LPBYTE dir, BOOL16 bIcon )
1617 {
1618     return LookupIconIdFromDirectoryEx16( 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  *              LookupIconIdFromDirectory (USER32.@)
1625  */
1626 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1627 {
1628     return LookupIconIdFromDirectoryEx( dir, bIcon,
1629            bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1630            bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1631 }
1632
1633 /**********************************************************************
1634  *              GetIconID (USER.455)
1635  */
1636 WORD WINAPI GetIconID16( HGLOBAL16 hResource, DWORD resType )
1637 {
1638     LPBYTE lpDir = (LPBYTE)GlobalLock16(hResource);
1639
1640     TRACE_(cursor)("hRes=%04x, entries=%i\n",
1641                     hResource, lpDir ? ((CURSORICONDIR*)lpDir)->idCount : 0);
1642
1643     switch(resType)
1644     {
1645         case RT_CURSOR:
1646              return (WORD)LookupIconIdFromDirectoryEx16( lpDir, FALSE,
1647                           GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1648         case RT_ICON:
1649              return (WORD)LookupIconIdFromDirectoryEx16( lpDir, TRUE,
1650                           GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0 );
1651         default:
1652              WARN_(cursor)("invalid res type %ld\n", resType );
1653     }
1654     return 0;
1655 }
1656
1657 /**********************************************************************
1658  *              LoadCursorIconHandler (USER.336)
1659  *
1660  * Supposed to load resources of Windows 2.x applications.
1661  */
1662 HGLOBAL16 WINAPI LoadCursorIconHandler16( HGLOBAL16 hResource, HMODULE16 hModule, HRSRC16 hRsrc )
1663 {
1664     FIXME_(cursor)("(%04x,%04x,%04x): old 2.x resources are not supported!\n",
1665           hResource, hModule, hRsrc);
1666     return (HGLOBAL16)0;
1667 }
1668
1669 /**********************************************************************
1670  *              LoadIconHandler (USER.456)
1671  */
1672 HICON16 WINAPI LoadIconHandler16( HGLOBAL16 hResource, BOOL16 bNew )
1673 {
1674     LPBYTE bits = (LPBYTE)LockResource16( hResource );
1675
1676     TRACE_(cursor)("hRes=%04x\n",hResource);
1677
1678     return HICON_16(CURSORICON_CreateFromResource(0, 0, bits, 0, TRUE,
1679                       bNew ? 0x00030000 : 0x00020000, 0, 0, LR_DEFAULTCOLOR));
1680 }
1681
1682 /***********************************************************************
1683  *              LoadCursorW (USER32.@)
1684  */
1685 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
1686 {
1687     return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0,
1688                        LR_SHARED | LR_DEFAULTSIZE );
1689 }
1690
1691 /***********************************************************************
1692  *              LoadCursorA (USER32.@)
1693  */
1694 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
1695 {
1696     return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0,
1697                        LR_SHARED | LR_DEFAULTSIZE );
1698 }
1699
1700 /***********************************************************************
1701  *              LoadCursorFromFileW (USER32.@)
1702  */
1703 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
1704 {
1705     return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0,
1706                        LR_LOADFROMFILE | LR_DEFAULTSIZE );
1707 }
1708
1709 /***********************************************************************
1710  *              LoadCursorFromFileA (USER32.@)
1711  */
1712 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
1713 {
1714     return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0,
1715                        LR_LOADFROMFILE | LR_DEFAULTSIZE );
1716 }
1717
1718 /***********************************************************************
1719  *              LoadIconW (USER32.@)
1720  */
1721 HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
1722 {
1723     return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0,
1724                        LR_SHARED | LR_DEFAULTSIZE );
1725 }
1726
1727 /***********************************************************************
1728  *              LoadIconA (USER32.@)
1729  */
1730 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
1731 {
1732     return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0,
1733                        LR_SHARED | LR_DEFAULTSIZE );
1734 }
1735
1736 /**********************************************************************
1737  *              GetIconInfo (USER32.@)
1738  */
1739 BOOL WINAPI GetIconInfo(HICON hIcon, PICONINFO iconinfo)
1740 {
1741     CURSORICONINFO *ciconinfo;
1742     INT height;
1743
1744     ciconinfo = GlobalLock16(HICON_16(hIcon));
1745     if (!ciconinfo)
1746         return FALSE;
1747
1748     if ( (ciconinfo->ptHotSpot.x == ICON_HOTSPOT) &&
1749          (ciconinfo->ptHotSpot.y == ICON_HOTSPOT) )
1750     {
1751       iconinfo->fIcon    = TRUE;
1752       iconinfo->xHotspot = ciconinfo->nWidth / 2;
1753       iconinfo->yHotspot = ciconinfo->nHeight / 2;
1754     }
1755     else
1756     {
1757       iconinfo->fIcon    = FALSE;
1758       iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
1759       iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
1760     }
1761
1762     if (ciconinfo->bBitsPerPixel > 1)
1763     {
1764         iconinfo->hbmColor = CreateBitmap( ciconinfo->nWidth, ciconinfo->nHeight,
1765                                 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
1766                                 (char *)(ciconinfo + 1)
1767                                 + ciconinfo->nHeight *
1768                                 get_bitmap_width_bytes (ciconinfo->nWidth,1) );
1769         height = ciconinfo->nHeight;
1770     }
1771     else
1772     {
1773         iconinfo->hbmColor = 0;
1774         height = ciconinfo->nHeight * 2;
1775     }
1776
1777     iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, height,
1778                                 1, 1, (char *)(ciconinfo + 1));
1779
1780     GlobalUnlock16(HICON_16(hIcon));
1781
1782     return TRUE;
1783 }
1784
1785 /**********************************************************************
1786  *              CreateIconIndirect (USER32.@)
1787  */
1788 HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
1789 {
1790     BITMAP bmpXor,bmpAnd;
1791     HICON16 hObj;
1792     int sizeXor,sizeAnd;
1793
1794     GetObjectA( iconinfo->hbmColor, sizeof(bmpXor), &bmpXor );
1795     GetObjectA( iconinfo->hbmMask, sizeof(bmpAnd), &bmpAnd );
1796
1797     sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
1798     sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
1799
1800     hObj = GlobalAlloc16( GMEM_MOVEABLE,
1801                           sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
1802     if (hObj)
1803     {
1804         CURSORICONINFO *info;
1805
1806         info = (CURSORICONINFO *)GlobalLock16( hObj );
1807
1808         /* If we are creating an icon, the hotspot is unused */
1809         if (iconinfo->fIcon)
1810         {
1811           info->ptHotSpot.x   = ICON_HOTSPOT;
1812           info->ptHotSpot.y   = ICON_HOTSPOT;
1813         }
1814         else
1815         {
1816           info->ptHotSpot.x   = iconinfo->xHotspot;
1817           info->ptHotSpot.y   = iconinfo->yHotspot;
1818         }
1819
1820         info->nWidth        = bmpXor.bmWidth;
1821         info->nHeight       = bmpXor.bmHeight;
1822         info->nWidthBytes   = bmpXor.bmWidthBytes;
1823         info->bPlanes       = bmpXor.bmPlanes;
1824         info->bBitsPerPixel = bmpXor.bmBitsPixel;
1825
1826         /* Transfer the bitmap bits to the CURSORICONINFO structure */
1827
1828         GetBitmapBits( iconinfo->hbmMask ,sizeAnd,(char*)(info + 1) );
1829         GetBitmapBits( iconinfo->hbmColor,sizeXor,(char*)(info + 1) +sizeAnd);
1830         GlobalUnlock16( hObj );
1831     }
1832     return HICON_32(hObj);
1833 }
1834
1835 /******************************************************************************
1836  *              DrawIconEx (USER32.@) Draws an icon or cursor on device context
1837  *
1838  * NOTES
1839  *    Why is this using SM_CXICON instead of SM_CXCURSOR?
1840  *
1841  * PARAMS
1842  *    hdc     [I] Handle to device context
1843  *    x0      [I] X coordinate of upper left corner
1844  *    y0      [I] Y coordinate of upper left corner
1845  *    hIcon   [I] Handle to icon to draw
1846  *    cxWidth [I] Width of icon
1847  *    cyWidth [I] Height of icon
1848  *    istep   [I] Index of frame in animated cursor
1849  *    hbr     [I] Handle to background brush
1850  *    flags   [I] Icon-drawing flags
1851  *
1852  * RETURNS
1853  *    Success: TRUE
1854  *    Failure: FALSE
1855  */
1856 BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
1857                             INT cxWidth, INT cyWidth, UINT istep,
1858                             HBRUSH hbr, UINT flags )
1859 {
1860     CURSORICONINFO *ptr = (CURSORICONINFO *)GlobalLock16(HICON_16(hIcon));
1861     HDC hDC_off = 0, hMemDC;
1862     BOOL result = FALSE, DoOffscreen;
1863     HBITMAP hB_off = 0, hOld = 0;
1864
1865     if (!ptr) return FALSE;
1866     TRACE_(icon)("(hdc=%p,pos=%d.%d,hicon=%p,extend=%d.%d,istep=%d,br=%p,flags=0x%08x)\n",
1867                  hdc,x0,y0,hIcon,cxWidth,cyWidth,istep,hbr,flags );
1868
1869     hMemDC = CreateCompatibleDC (hdc);
1870     if (istep)
1871         FIXME_(icon)("Ignoring istep=%d\n", istep);
1872     if (flags & DI_COMPAT)
1873         FIXME_(icon)("Ignoring flag DI_COMPAT\n");
1874
1875     if (!flags) {
1876         FIXME_(icon)("no flags set? setting to DI_NORMAL\n");
1877         flags = DI_NORMAL;
1878     }
1879
1880     /* Calculate the size of the destination image.  */
1881     if (cxWidth == 0)
1882     {
1883         if (flags & DI_DEFAULTSIZE)
1884             cxWidth = GetSystemMetrics (SM_CXICON);
1885         else
1886             cxWidth = ptr->nWidth;
1887     }
1888     if (cyWidth == 0)
1889     {
1890         if (flags & DI_DEFAULTSIZE)
1891             cyWidth = GetSystemMetrics (SM_CYICON);
1892         else
1893             cyWidth = ptr->nHeight;
1894     }
1895
1896     DoOffscreen = (GetObjectType( hbr ) == OBJ_BRUSH);
1897
1898     if (DoOffscreen) {
1899         RECT r;
1900
1901         r.left = 0;
1902         r.top = 0;
1903         r.right = cxWidth;
1904         r.bottom = cxWidth;
1905
1906         hDC_off = CreateCompatibleDC(hdc);
1907         hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth);
1908         if (hDC_off && hB_off) {
1909             hOld = SelectObject(hDC_off, hB_off);
1910             FillRect(hDC_off, &r, hbr);
1911         }
1912     }
1913
1914     if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
1915     {
1916         HBITMAP hXorBits, hAndBits;
1917         COLORREF  oldFg, oldBg;
1918         INT     nStretchMode;
1919
1920         nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
1921
1922         hXorBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1923                                   ptr->bPlanes, ptr->bBitsPerPixel,
1924                                   (char *)(ptr + 1)
1925                                   + ptr->nHeight *
1926                                   get_bitmap_width_bytes(ptr->nWidth,1) );
1927         hAndBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1928                                   1, 1, (char *)(ptr+1) );
1929         oldFg = SetTextColor( hdc, RGB(0,0,0) );
1930         oldBg = SetBkColor( hdc, RGB(255,255,255) );
1931
1932         if (hXorBits && hAndBits)
1933         {
1934             HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1935             if (flags & DI_MASK)
1936             {
1937                 if (DoOffscreen)
1938                     StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1939                                 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1940                 else
1941                     StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
1942                                 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1943             }
1944             SelectObject( hMemDC, hXorBits );
1945             if (flags & DI_IMAGE)
1946             {
1947                 if (DoOffscreen)
1948                     StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1949                                 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
1950                 else
1951                     StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
1952                                 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
1953             }
1954             SelectObject( hMemDC, hBitTemp );
1955             result = TRUE;
1956         }
1957
1958         SetTextColor( hdc, oldFg );
1959         SetBkColor( hdc, oldBg );
1960         if (hXorBits) DeleteObject( hXorBits );
1961         if (hAndBits) DeleteObject( hAndBits );
1962         SetStretchBltMode (hdc, nStretchMode);
1963         if (DoOffscreen) {
1964             BitBlt(hdc, x0, y0, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
1965             SelectObject(hDC_off, hOld);
1966         }
1967     }
1968     if (hMemDC) DeleteDC( hMemDC );
1969     if (hDC_off) DeleteDC(hDC_off);
1970     if (hB_off) DeleteObject(hB_off);
1971     GlobalUnlock16(HICON_16(hIcon));
1972     return result;
1973 }
1974
1975 /***********************************************************************
1976  *           DIB_FixColorsToLoadflags
1977  *
1978  * Change color table entries when LR_LOADTRANSPARENT or LR_LOADMAP3DCOLORS
1979  * are in loadflags
1980  */
1981 static void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags, BYTE pix)
1982 {
1983     int colors;
1984     COLORREF c_W, c_S, c_F, c_L, c_C;
1985     int incr,i;
1986     RGBQUAD *ptr;
1987     int bitmap_type;
1988     LONG width;
1989     LONG height;
1990     WORD bpp;
1991     DWORD compr;
1992
1993     if (((bitmap_type = DIB_GetBitmapInfo((BITMAPINFOHEADER*) bmi, &width, &height, &bpp, &compr)) == -1))
1994     {
1995         WARN_(resource)("Invalid bitmap\n");
1996         return;
1997     }
1998
1999     if (bpp > 8) return;
2000
2001     if (bitmap_type == 0) /* BITMAPCOREHEADER */
2002     {
2003         incr = 3;
2004         colors = 1 << bpp;
2005     }
2006     else
2007     {
2008         incr = 4;
2009         colors = bmi->bmiHeader.biClrUsed;
2010         if (colors > 256) colors = 256;
2011         if (!colors && (bpp <= 8)) colors = 1 << bpp;
2012     }
2013
2014     c_W = GetSysColor(COLOR_WINDOW);
2015     c_S = GetSysColor(COLOR_3DSHADOW);
2016     c_F = GetSysColor(COLOR_3DFACE);
2017     c_L = GetSysColor(COLOR_3DLIGHT);
2018
2019     if (loadflags & LR_LOADTRANSPARENT) {
2020         switch (bpp) {
2021         case 1: pix = pix >> 7; break;
2022         case 4: pix = pix >> 4; break;
2023         case 8: break;
2024         default:
2025             WARN_(resource)("(%d): Unsupported depth\n", bpp);
2026             return;
2027         }
2028         if (pix >= colors) {
2029             WARN_(resource)("pixel has color index greater than biClrUsed!\n");
2030             return;
2031         }
2032         if (loadflags & LR_LOADMAP3DCOLORS) c_W = c_F;
2033         ptr = (RGBQUAD*)((char*)bmi->bmiColors+pix*incr);
2034         ptr->rgbBlue = GetBValue(c_W);
2035         ptr->rgbGreen = GetGValue(c_W);
2036         ptr->rgbRed = GetRValue(c_W);
2037     }
2038     if (loadflags & LR_LOADMAP3DCOLORS)
2039         for (i=0; i<colors; i++) {
2040             ptr = (RGBQUAD*)((char*)bmi->bmiColors+i*incr);
2041             c_C = RGB(ptr->rgbRed, ptr->rgbGreen, ptr->rgbBlue);
2042             if (c_C == RGB(128, 128, 128)) {
2043                 ptr->rgbRed = GetRValue(c_S);
2044                 ptr->rgbGreen = GetGValue(c_S);
2045                 ptr->rgbBlue = GetBValue(c_S);
2046             } else if (c_C == RGB(192, 192, 192)) {
2047                 ptr->rgbRed = GetRValue(c_F);
2048                 ptr->rgbGreen = GetGValue(c_F);
2049                 ptr->rgbBlue = GetBValue(c_F);
2050             } else if (c_C == RGB(223, 223, 223)) {
2051                 ptr->rgbRed = GetRValue(c_L);
2052                 ptr->rgbGreen = GetGValue(c_L);
2053                 ptr->rgbBlue = GetBValue(c_L);
2054             }
2055         }
2056 }
2057
2058
2059 /**********************************************************************
2060  *       BITMAP_Load
2061  */
2062 static HBITMAP BITMAP_Load( HINSTANCE instance, LPCWSTR name,
2063                             INT desiredx, INT desiredy, UINT loadflags )
2064 {
2065     HBITMAP hbitmap = 0, orig_bm;
2066     HRSRC hRsrc;
2067     HGLOBAL handle;
2068     char *ptr = NULL;
2069     BITMAPINFO *info, *fix_info = NULL, *scaled_info = NULL;
2070     int size;
2071     BYTE pix;
2072     char *bits;
2073     LONG width, height, new_width, new_height;
2074     WORD bpp_dummy;
2075     DWORD compr_dummy;
2076     INT bm_type;
2077     HDC screen_mem_dc = NULL;
2078
2079     if (!(loadflags & LR_LOADFROMFILE))
2080     {
2081         if (!instance)
2082         {
2083             /* OEM bitmap: try to load the resource from user32.dll */
2084             if (HIWORD(name)) return 0;
2085             instance = user32_module;
2086         }
2087
2088         if (!(hRsrc = FindResourceW( instance, name, (LPWSTR)RT_BITMAP ))) return 0;
2089         if (!(handle = LoadResource( instance, hRsrc ))) return 0;
2090
2091         if ((info = (BITMAPINFO *)LockResource( handle )) == NULL) return 0;
2092     }
2093     else
2094     {
2095         if (!(ptr = map_fileW( name, NULL ))) return 0;
2096         info = (BITMAPINFO *)(ptr + sizeof(BITMAPFILEHEADER));
2097     }
2098
2099     size = bitmap_info_size(info, DIB_RGB_COLORS);
2100     fix_info = HeapAlloc(GetProcessHeap(), 0, size);
2101     scaled_info = HeapAlloc(GetProcessHeap(), 0, size);
2102
2103     if (!fix_info || !scaled_info) goto end;
2104     memcpy(fix_info, info, size);
2105
2106     pix = *((LPBYTE)info + size);
2107     DIB_FixColorsToLoadflags(fix_info, loadflags, pix);
2108
2109     memcpy(scaled_info, fix_info, size);
2110     bm_type = DIB_GetBitmapInfo( &fix_info->bmiHeader, &width, &height,
2111                                  &bpp_dummy, &compr_dummy);
2112     if(desiredx != 0)
2113         new_width = desiredx;
2114     else
2115         new_width = width;
2116
2117     if(desiredy != 0)
2118         new_height = height > 0 ? desiredy : -desiredy;
2119     else
2120         new_height = height;
2121
2122     if(bm_type == 0)
2123     {
2124         BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)&scaled_info->bmiHeader;
2125         core->bcWidth = new_width;
2126         core->bcHeight = new_height;
2127     }
2128     else
2129     {
2130         scaled_info->bmiHeader.biWidth = new_width;
2131         scaled_info->bmiHeader.biHeight = new_height;
2132     }
2133
2134     if (new_height < 0) new_height = -new_height;
2135
2136     if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
2137     if (!(screen_mem_dc = CreateCompatibleDC( screen_dc ))) goto end;
2138
2139     bits = (char *)info + size;
2140
2141     if (loadflags & LR_CREATEDIBSECTION)
2142     {
2143         scaled_info->bmiHeader.biCompression = 0; /* DIBSection can't be compressed */
2144         hbitmap = CreateDIBSection(screen_dc, scaled_info, DIB_RGB_COLORS, NULL, 0, 0);
2145     }
2146     else
2147     {
2148         if (is_dib_monochrome(fix_info))
2149             hbitmap = CreateBitmap(new_width, new_height, 1, 1, NULL);
2150         else
2151             hbitmap = CreateCompatibleBitmap(screen_dc, new_width, new_height);        
2152     }
2153
2154     orig_bm = SelectObject(screen_mem_dc, hbitmap);
2155     StretchDIBits(screen_mem_dc, 0, 0, new_width, new_height, 0, 0, width, height, bits, fix_info, DIB_RGB_COLORS, SRCCOPY);
2156     SelectObject(screen_mem_dc, orig_bm);
2157
2158 end:
2159     if (screen_mem_dc) DeleteDC(screen_mem_dc);
2160     HeapFree(GetProcessHeap(), 0, scaled_info);
2161     HeapFree(GetProcessHeap(), 0, fix_info);
2162     if (loadflags & LR_LOADFROMFILE) UnmapViewOfFile( ptr );
2163
2164     return hbitmap;
2165 }
2166
2167 /**********************************************************************
2168  *              LoadImageA (USER32.@)
2169  *
2170  * FIXME: implementation lacks some features, see LR_ defines in winuser.h
2171  */
2172
2173 /* filter for page-fault exceptions */
2174 static WINE_EXCEPTION_FILTER(page_fault)
2175 {
2176     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
2177         return EXCEPTION_EXECUTE_HANDLER;
2178     return EXCEPTION_CONTINUE_SEARCH;
2179 }
2180
2181 /*********************************************************************/
2182
2183 HANDLE WINAPI LoadImageA( HINSTANCE hinst, LPCSTR name, UINT type,
2184                               INT desiredx, INT desiredy, UINT loadflags)
2185 {
2186     HANDLE res;
2187     LPWSTR u_name;
2188
2189     if (!HIWORD(name))
2190         return LoadImageW(hinst, (LPCWSTR)name, type, desiredx, desiredy, loadflags);
2191
2192     __TRY {
2193         DWORD len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
2194         u_name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2195         MultiByteToWideChar( CP_ACP, 0, name, -1, u_name, len );
2196     }
2197     __EXCEPT(page_fault) {
2198         SetLastError( ERROR_INVALID_PARAMETER );
2199         return 0;
2200     }
2201     __ENDTRY
2202     res = LoadImageW(hinst, u_name, type, desiredx, desiredy, loadflags);
2203     HeapFree(GetProcessHeap(), 0, u_name);
2204     return res;
2205 }
2206
2207
2208 /******************************************************************************
2209  *              LoadImageW (USER32.@) Loads an icon, cursor, or bitmap
2210  *
2211  * PARAMS
2212  *    hinst     [I] Handle of instance that contains image
2213  *    name      [I] Name of image
2214  *    type      [I] Type of image
2215  *    desiredx  [I] Desired width
2216  *    desiredy  [I] Desired height
2217  *    loadflags [I] Load flags
2218  *
2219  * RETURNS
2220  *    Success: Handle to newly loaded image
2221  *    Failure: NULL
2222  *
2223  * FIXME: Implementation lacks some features, see LR_ defines in winuser.h
2224  */
2225 HANDLE WINAPI LoadImageW( HINSTANCE hinst, LPCWSTR name, UINT type,
2226                 INT desiredx, INT desiredy, UINT loadflags )
2227 {
2228     if (HIWORD(name)) {
2229         TRACE_(resource)("(%p,%p,%d,%d,%d,0x%08x)\n",
2230               hinst,name,type,desiredx,desiredy,loadflags);
2231     } else {
2232         TRACE_(resource)("(%p,%p,%d,%d,%d,0x%08x)\n",
2233               hinst,name,type,desiredx,desiredy,loadflags);
2234     }
2235     if (loadflags & LR_DEFAULTSIZE) {
2236         if (type == IMAGE_ICON) {
2237             if (!desiredx) desiredx = GetSystemMetrics(SM_CXICON);
2238             if (!desiredy) desiredy = GetSystemMetrics(SM_CYICON);
2239         } else if (type == IMAGE_CURSOR) {
2240             if (!desiredx) desiredx = GetSystemMetrics(SM_CXCURSOR);
2241             if (!desiredy) desiredy = GetSystemMetrics(SM_CYCURSOR);
2242         }
2243     }
2244     if (loadflags & LR_LOADFROMFILE) loadflags &= ~LR_SHARED;
2245     switch (type) {
2246     case IMAGE_BITMAP:
2247         return BITMAP_Load( hinst, name, desiredx, desiredy, loadflags );
2248
2249     case IMAGE_ICON:
2250         if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
2251         if (screen_dc)
2252         {
2253             UINT palEnts = GetSystemPaletteEntries(screen_dc, 0, 0, NULL);
2254             if (palEnts == 0) palEnts = 256;
2255             return CURSORICON_Load(hinst, name, desiredx, desiredy,
2256                                    palEnts, FALSE, loadflags);
2257         }
2258         break;
2259
2260     case IMAGE_CURSOR:
2261         return CURSORICON_Load(hinst, name, desiredx, desiredy,
2262                                1, TRUE, loadflags);
2263     }
2264     return 0;
2265 }
2266
2267 /******************************************************************************
2268  *              CopyImage (USER32.@) Creates new image and copies attributes to it
2269  *
2270  * PARAMS
2271  *    hnd      [I] Handle to image to copy
2272  *    type     [I] Type of image to copy
2273  *    desiredx [I] Desired width of new image
2274  *    desiredy [I] Desired height of new image
2275  *    flags    [I] Copy flags
2276  *
2277  * RETURNS
2278  *    Success: Handle to newly created image
2279  *    Failure: NULL
2280  *
2281  * FIXME: implementation still lacks nearly all features, see LR_*
2282  * defines in winuser.h
2283  */
2284 HICON WINAPI CopyImage( HANDLE hnd, UINT type, INT desiredx,
2285                              INT desiredy, UINT flags )
2286 {
2287     switch (type)
2288     {
2289         case IMAGE_BITMAP:
2290         {
2291             HBITMAP res;
2292             BITMAP bm;
2293
2294             if (!GetObjectW( hnd, sizeof(bm), &bm )) return 0;
2295             bm.bmBits = NULL;
2296             if ((res = CreateBitmapIndirect(&bm)))
2297             {
2298                 char *buf = HeapAlloc( GetProcessHeap(), 0, bm.bmWidthBytes * bm.bmHeight );
2299                 GetBitmapBits( hnd, bm.bmWidthBytes * bm.bmHeight, buf );
2300                 SetBitmapBits( res, bm.bmWidthBytes * bm.bmHeight, buf );
2301                 HeapFree( GetProcessHeap(), 0, buf );
2302             }
2303             return (HICON)res;
2304         }
2305         case IMAGE_ICON:
2306                 return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags);
2307         case IMAGE_CURSOR:
2308                 /* Should call CURSORICON_ExtCopy but more testing
2309                  * needs to be done before we change this
2310                  */
2311                 return CopyCursor(hnd);
2312     }
2313     return 0;
2314 }
2315
2316
2317 /******************************************************************************
2318  *              LoadBitmapW (USER32.@) Loads bitmap from the executable file
2319  *
2320  * RETURNS
2321  *    Success: Handle to specified bitmap
2322  *    Failure: NULL
2323  */
2324 HBITMAP WINAPI LoadBitmapW(
2325     HINSTANCE instance, /* [in] Handle to application instance */
2326     LPCWSTR name)         /* [in] Address of bitmap resource name */
2327 {
2328     return LoadImageW( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2329 }
2330
2331 /**********************************************************************
2332  *              LoadBitmapA (USER32.@)
2333  */
2334 HBITMAP WINAPI LoadBitmapA( HINSTANCE instance, LPCSTR name )
2335 {
2336     return LoadImageA( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2337 }