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