Store the current cursor in the thread queue instead of globally.
[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 "queue.h"
60 #include "input.h"
61 #include "message.h"
62 #include "winerror.h"
63 #include "msvcrt/excpt.h"
64
65 WINE_DECLARE_DEBUG_CHANNEL(cursor);
66 WINE_DECLARE_DEBUG_CHANNEL(icon);
67 WINE_DECLARE_DEBUG_CHANNEL(resource);
68
69 static RECT CURSOR_ClipRect;       /* Cursor clipping rect */
70
71 static HDC screen_dc;
72
73 /**********************************************************************
74  * ICONCACHE for cursors/icons loaded with LR_SHARED.
75  *
76  * FIXME: This should not be allocated on the system heap, but on a
77  *        subsystem-global heap (i.e. one for all Win16 processes,
78  *        and one for each Win32 process).
79  */
80 typedef struct tagICONCACHE
81 {
82     struct tagICONCACHE *next;
83
84     HMODULE              hModule;
85     HRSRC                hRsrc;
86     HRSRC                hGroupRsrc;
87     HANDLE               handle;
88
89     INT                  count;
90
91 } ICONCACHE;
92
93 static ICONCACHE *IconAnchor = NULL;
94 static CRITICAL_SECTION IconCrst = CRITICAL_SECTION_INIT("IconCrst");
95 static WORD ICON_HOTSPOT = 0x4242;
96
97
98 /***********************************************************************
99  *             map_fileW
100  *
101  * Helper function to map a file to memory:
102  *  name                        -       file name
103  *  [RETURN] ptr                -       pointer to mapped file
104  */
105 static void *map_fileW( LPCWSTR name )
106 {
107     HANDLE hFile, hMapping;
108     LPVOID ptr = NULL;
109
110     hFile = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL,
111                          OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0 );
112     if (hFile != INVALID_HANDLE_VALUE)
113     {
114         hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
115         CloseHandle( hFile );
116         if (hMapping)
117         {
118             ptr = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
119             CloseHandle( hMapping );
120         }
121     }
122     return ptr;
123 }
124
125
126 /**********************************************************************
127  *          CURSORICON_FindSharedIcon
128  */
129 static HANDLE CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
130 {
131     HANDLE handle = 0;
132     ICONCACHE *ptr;
133
134     EnterCriticalSection( &IconCrst );
135
136     for ( ptr = IconAnchor; ptr; ptr = ptr->next )
137         if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
138         {
139             ptr->count++;
140             handle = ptr->handle;
141             break;
142         }
143
144     LeaveCriticalSection( &IconCrst );
145
146     return handle;
147 }
148
149 /*************************************************************************
150  * CURSORICON_FindCache
151  *
152  * Given a handle, find the corresponding cache element
153  *
154  * PARAMS
155  *      Handle     [I] handle to an Image
156  *
157  * RETURNS
158  *     Success: The cache entry
159  *     Failure: NULL
160  *
161  */
162 static ICONCACHE* CURSORICON_FindCache(HANDLE handle)
163 {
164     ICONCACHE *ptr;
165     ICONCACHE *pRet=NULL;
166     BOOL IsFound = FALSE;
167     int count;
168
169     EnterCriticalSection( &IconCrst );
170
171     for (count = 0, ptr = IconAnchor; ptr != NULL && !IsFound; ptr = ptr->next, count++ )
172     {
173         if ( handle == ptr->handle )
174         {
175             IsFound = TRUE;
176             pRet = ptr;
177         }
178     }
179
180     LeaveCriticalSection( &IconCrst );
181
182     return pRet;
183 }
184
185 /**********************************************************************
186  *          CURSORICON_AddSharedIcon
187  */
188 static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HRSRC hGroupRsrc, HANDLE handle )
189 {
190     ICONCACHE *ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(ICONCACHE) );
191     if ( !ptr ) return;
192
193     ptr->hModule = hModule;
194     ptr->hRsrc   = hRsrc;
195     ptr->handle  = handle;
196     ptr->hGroupRsrc = hGroupRsrc;
197     ptr->count   = 1;
198
199     EnterCriticalSection( &IconCrst );
200     ptr->next    = IconAnchor;
201     IconAnchor   = ptr;
202     LeaveCriticalSection( &IconCrst );
203 }
204
205 /**********************************************************************
206  *          CURSORICON_DelSharedIcon
207  */
208 static INT CURSORICON_DelSharedIcon( HANDLE handle )
209 {
210     INT count = -1;
211     ICONCACHE *ptr;
212
213     EnterCriticalSection( &IconCrst );
214
215     for ( ptr = IconAnchor; ptr; ptr = ptr->next )
216         if ( ptr->handle == handle )
217         {
218             if ( ptr->count > 0 ) ptr->count--;
219             count = ptr->count;
220             break;
221         }
222
223     LeaveCriticalSection( &IconCrst );
224
225     return count;
226 }
227
228 /**********************************************************************
229  *          CURSORICON_FreeModuleIcons
230  */
231 void CURSORICON_FreeModuleIcons( HMODULE hModule )
232 {
233     ICONCACHE **ptr = &IconAnchor;
234
235     if ( HIWORD( hModule ) )
236         hModule = MapHModuleLS( hModule );
237     else
238         hModule = GetExePtr( hModule );
239
240     EnterCriticalSection( &IconCrst );
241
242     while ( *ptr )
243     {
244         if ( (*ptr)->hModule == hModule )
245         {
246             ICONCACHE *freePtr = *ptr;
247             *ptr = freePtr->next;
248
249             GlobalFree16( freePtr->handle );
250             HeapFree( GetProcessHeap(), 0, freePtr );
251             continue;
252         }
253         ptr = &(*ptr)->next;
254     }
255
256     LeaveCriticalSection( &IconCrst );
257 }
258
259 /**********************************************************************
260  *          CURSORICON_FindBestIcon
261  *
262  * Find the icon closest to the requested size and number of colors.
263  */
264 static CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
265                                               int height, int colors )
266 {
267     int i;
268     CURSORICONDIRENTRY *entry, *bestEntry = NULL;
269     UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
270     UINT iTempXDiff, iTempYDiff, iTempColorDiff;
271
272     if (dir->idCount < 1)
273     {
274         WARN_(icon)("Empty directory!\n" );
275         return NULL;
276     }
277     if (dir->idCount == 1) return &dir->idEntries[0];  /* No choice... */
278
279     /* Find Best Fit */
280     iTotalDiff = 0xFFFFFFFF;
281     iColorDiff = 0xFFFFFFFF;
282     for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
283         {
284         iTempXDiff = abs(width - entry->ResInfo.icon.bWidth);
285         iTempYDiff = abs(height - entry->ResInfo.icon.bHeight);
286
287         if(iTotalDiff > (iTempXDiff + iTempYDiff))
288         {
289             iXDiff = iTempXDiff;
290             iYDiff = iTempYDiff;
291             iTotalDiff = iXDiff + iYDiff;
292         }
293         }
294
295     /* Find Best Colors for Best Fit */
296     for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
297         {
298         if(abs(width - entry->ResInfo.icon.bWidth) == iXDiff &&
299             abs(height - entry->ResInfo.icon.bHeight) == iYDiff)
300         {
301             iTempColorDiff = abs(colors - entry->ResInfo.icon.bColorCount);
302             if(iColorDiff > iTempColorDiff)
303         {
304             bestEntry = entry;
305                 iColorDiff = iTempColorDiff;
306         }
307         }
308     }
309
310     return bestEntry;
311 }
312
313
314 /**********************************************************************
315  *          CURSORICON_FindBestCursor
316  *
317  * Find the cursor closest to the requested size.
318  * FIXME: parameter 'color' ignored and entries with more than 1 bpp
319  *        ignored too
320  */
321 static CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
322                                                   int width, int height, int color)
323 {
324     int i, maxwidth, maxheight;
325     CURSORICONDIRENTRY *entry, *bestEntry = NULL;
326
327     if (dir->idCount < 1)
328     {
329         WARN_(cursor)("Empty directory!\n" );
330         return NULL;
331     }
332     if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
333
334     /* Double height to account for AND and XOR masks */
335
336     height *= 2;
337
338     /* First find the largest one smaller than or equal to the requested size*/
339
340     maxwidth = maxheight = 0;
341     for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
342         if ((entry->ResInfo.cursor.wWidth <= width) && (entry->ResInfo.cursor.wHeight <= height) &&
343             (entry->ResInfo.cursor.wWidth > maxwidth) && (entry->ResInfo.cursor.wHeight > maxheight) &&
344             (entry->wBitCount == 1))
345         {
346             bestEntry = entry;
347             maxwidth  = entry->ResInfo.cursor.wWidth;
348             maxheight = entry->ResInfo.cursor.wHeight;
349         }
350     if (bestEntry) return bestEntry;
351
352     /* Now find the smallest one larger than the requested size */
353
354     maxwidth = maxheight = 255;
355     for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
356         if ((entry->ResInfo.cursor.wWidth < maxwidth) && (entry->ResInfo.cursor.wHeight < maxheight) &&
357             (entry->wBitCount == 1))
358         {
359             bestEntry = entry;
360             maxwidth  = entry->ResInfo.cursor.wWidth;
361             maxheight = entry->ResInfo.cursor.wHeight;
362         }
363
364     return bestEntry;
365 }
366
367 /*********************************************************************
368  * The main purpose of this function is to create fake resource directory
369  * and fake resource entries. There are several reasons for this:
370  *      -       CURSORICONDIR and CURSORICONFILEDIR differ in sizes and their
371  *              fields
372  *      There are some "bad" cursor files which do not have
373  *              bColorCount initialized but instead one must read this info
374  *              directly from corresponding DIB sections
375  * Note: wResId is index to array of pointer returned in ptrs (origin is 1)
376  */
377 BOOL CURSORICON_SimulateLoadingFromResourceW( LPWSTR filename, BOOL fCursor,
378                                                 CURSORICONDIR **res, LPBYTE **ptr)
379 {
380     LPBYTE   _free;
381     CURSORICONFILEDIR *bits;
382     int      entries, size, i;
383
384     *res = NULL;
385     *ptr = NULL;
386     if (!(bits = map_fileW( filename ))) return FALSE;
387
388     /* FIXME: test for inimated icons
389      * hack to load the first icon from the *.ani file
390      */
391     if ( *(LPDWORD)bits==0x46464952 ) /* "RIFF" */
392     { LPBYTE pos = (LPBYTE) bits;
393       FIXME_(cursor)("Animated icons not correctly implemented! %p \n", bits);
394
395       for (;;)
396       { if (*(LPDWORD)pos==0x6e6f6369)          /* "icon" */
397         { FIXME_(cursor)("icon entry found! %p\n", bits);
398           pos+=4;
399           if ( !*(LPWORD) pos==0x2fe)           /* iconsize */
400           { goto fail;
401           }
402           bits=(CURSORICONFILEDIR*)(pos+4);
403           FIXME_(cursor)("icon size ok. offset=%p \n", bits);
404           break;
405         }
406         pos+=2;
407         if (pos>=(LPBYTE)bits+766) goto fail;
408       }
409     }
410     if (!(entries = bits->idCount)) goto fail;
411     size = sizeof(CURSORICONDIR) + sizeof(CURSORICONDIRENTRY) * (entries - 1);
412     _free = (LPBYTE) size;
413
414     for (i=0; i < entries; i++)
415       size += bits->idEntries[i].dwDIBSize + (fCursor ? sizeof(POINT16): 0);
416
417     if (!(*ptr = HeapAlloc( GetProcessHeap(), 0,
418                             entries * sizeof (CURSORICONDIRENTRY*)))) goto fail;
419     if (!(*res = HeapAlloc( GetProcessHeap(), 0, size))) goto fail;
420
421     _free = (LPBYTE)(*res) + (int)_free;
422     memcpy((*res), bits, 6);
423     for (i=0; i<entries; i++)
424     {
425       ((LPBYTE*)(*ptr))[i] = _free;
426       if (fCursor) {
427         (*res)->idEntries[i].ResInfo.cursor.wWidth=bits->idEntries[i].bWidth;
428         (*res)->idEntries[i].ResInfo.cursor.wHeight=bits->idEntries[i].bHeight;
429         ((LPPOINT16)_free)->x=bits->idEntries[i].xHotspot;
430         ((LPPOINT16)_free)->y=bits->idEntries[i].yHotspot;
431         _free+=sizeof(POINT16);
432       } else {
433         (*res)->idEntries[i].ResInfo.icon.bWidth=bits->idEntries[i].bWidth;
434         (*res)->idEntries[i].ResInfo.icon.bHeight=bits->idEntries[i].bHeight;
435         (*res)->idEntries[i].ResInfo.icon.bColorCount = bits->idEntries[i].bColorCount;
436       }
437       (*res)->idEntries[i].wPlanes=1;
438       (*res)->idEntries[i].wBitCount = ((LPBITMAPINFOHEADER)((LPBYTE)bits +
439                                                    bits->idEntries[i].dwDIBOffset))->biBitCount;
440       (*res)->idEntries[i].dwBytesInRes = bits->idEntries[i].dwDIBSize;
441       (*res)->idEntries[i].wResId=i+1;
442
443       memcpy(_free,(LPBYTE)bits +bits->idEntries[i].dwDIBOffset,
444              (*res)->idEntries[i].dwBytesInRes);
445       _free += (*res)->idEntries[i].dwBytesInRes;
446     }
447     UnmapViewOfFile( bits );
448     return TRUE;
449 fail:
450     if (*res) HeapFree( GetProcessHeap(), 0, *res );
451     if (*ptr) HeapFree( GetProcessHeap(), 0, *ptr );
452     UnmapViewOfFile( bits );
453     return FALSE;
454 }
455
456
457 /**********************************************************************
458  *          CURSORICON_CreateFromResource
459  *
460  * Create a cursor or icon from in-memory resource template.
461  *
462  * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
463  *        with cbSize parameter as well.
464  */
465 static HGLOBAL16 CURSORICON_CreateFromResource( HINSTANCE16 hInstance, HGLOBAL16 hObj, LPBYTE bits,
466                                                 UINT cbSize, BOOL bIcon, DWORD dwVersion,
467                                                 INT width, INT height, UINT loadflags )
468 {
469     static HDC hdcMem;
470     int sizeAnd, sizeXor;
471     HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
472     BITMAP bmpXor, bmpAnd;
473     POINT16 hotspot;
474     BITMAPINFO *bmi;
475     BOOL DoStretch;
476     INT size;
477
478     hotspot.x = ICON_HOTSPOT;
479     hotspot.y = ICON_HOTSPOT;
480
481     TRACE_(cursor)("%08x (%u bytes), ver %08x, %ix%i %s %s\n",
482                         (unsigned)bits, cbSize, (unsigned)dwVersion, width, height,
483                                   bIcon ? "icon" : "cursor", (loadflags & LR_MONOCHROME) ? "mono" : "" );
484     if (dwVersion == 0x00020000)
485     {
486         FIXME_(cursor)("\t2.xx resources are not supported\n");
487         return 0;
488     }
489
490     if (bIcon)
491         bmi = (BITMAPINFO *)bits;
492     else /* get the hotspot */
493     {
494         POINT16 *pt = (POINT16 *)bits;
495         hotspot = *pt;
496         bmi = (BITMAPINFO *)(pt + 1);
497     }
498     size = DIB_BitmapInfoSize( bmi, DIB_RGB_COLORS );
499
500     if (!width) width = bmi->bmiHeader.biWidth;
501     if (!height) height = bmi->bmiHeader.biHeight/2;
502     DoStretch = (bmi->bmiHeader.biHeight/2 != height) ||
503       (bmi->bmiHeader.biWidth != width);
504
505     /* Check bitmap header */
506
507     if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
508          (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)  ||
509           bmi->bmiHeader.biCompression != BI_RGB) )
510     {
511           WARN_(cursor)("\tinvalid resource bitmap header.\n");
512           return 0;
513     }
514
515     if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
516     if (screen_dc)
517     {
518         BITMAPINFO* pInfo;
519
520         /* Make sure we have room for the monochrome bitmap later on.
521          * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
522          * up to and including the biBitCount. In-memory icon resource
523          * format is as follows:
524          *
525          *   BITMAPINFOHEADER   icHeader  // DIB header
526          *   RGBQUAD         icColors[]   // Color table
527          *   BYTE            icXOR[]      // DIB bits for XOR mask
528          *   BYTE            icAND[]      // DIB bits for AND mask
529          */
530
531         if ((pInfo = (BITMAPINFO *)HeapAlloc( GetProcessHeap(), 0,
532           max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))))
533         {
534             memcpy( pInfo, bmi, size );
535             pInfo->bmiHeader.biHeight /= 2;
536
537             /* Create the XOR bitmap */
538
539             if (DoStretch) {
540                 if(bIcon)
541                 {
542                     hXorBits = CreateCompatibleBitmap(screen_dc, width, height);
543                 }
544                 else
545                 {
546                     hXorBits = CreateBitmap(width, height, 1, 1, NULL);
547                 }
548                 if(hXorBits)
549                 {
550                 HBITMAP hOld;
551                 BOOL res = FALSE;
552
553                 if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
554                 if (hdcMem) {
555                     hOld = SelectObject(hdcMem, hXorBits);
556                     res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
557                                         bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2,
558                                         (char*)bmi + size, pInfo, DIB_RGB_COLORS, SRCCOPY);
559                     SelectObject(hdcMem, hOld);
560                 }
561                 if (!res) { DeleteObject(hXorBits); hXorBits = 0; }
562               }
563             } else hXorBits = CreateDIBitmap( screen_dc, &pInfo->bmiHeader,
564                 CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS );
565             if( hXorBits )
566             {
567                 char* xbits = (char *)bmi + size +
568                         DIB_GetDIBImageBytes(bmi->bmiHeader.biWidth,
569                                              bmi->bmiHeader.biHeight,
570                                              bmi->bmiHeader.biBitCount) / 2;
571
572                 pInfo->bmiHeader.biBitCount = 1;
573                 if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
574                 {
575                     RGBQUAD *rgb = pInfo->bmiColors;
576
577                     pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
578                     rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
579                     rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
580                     rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
581                 }
582                 else
583                 {
584                     RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
585
586                     rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
587                     rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
588                 }
589
590                 /* Create the AND bitmap */
591
592             if (DoStretch) {
593               if ((hAndBits = CreateBitmap(width, height, 1, 1, NULL))) {
594                 HBITMAP hOld;
595                 BOOL res = FALSE;
596
597                 if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
598                 if (hdcMem) {
599                     hOld = SelectObject(hdcMem, hAndBits);
600                     res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
601                                         pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight,
602                                         xbits, pInfo, DIB_RGB_COLORS, SRCCOPY);
603                     SelectObject(hdcMem, hOld);
604                 }
605                 if (!res) { DeleteObject(hAndBits); hAndBits = 0; }
606               }
607             } else hAndBits = CreateDIBitmap( screen_dc, &pInfo->bmiHeader,
608               CBM_INIT, xbits, pInfo, DIB_RGB_COLORS );
609
610                 if( !hAndBits ) DeleteObject( hXorBits );
611             }
612             HeapFree( GetProcessHeap(), 0, pInfo );
613         }
614     }
615
616     if( !hXorBits || !hAndBits )
617     {
618         WARN_(cursor)("\tunable to create an icon bitmap.\n");
619         return 0;
620     }
621
622     /* Now create the CURSORICONINFO structure */
623     GetObjectA( hXorBits, sizeof(bmpXor), &bmpXor );
624     GetObjectA( hAndBits, sizeof(bmpAnd), &bmpAnd );
625     sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
626     sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
627
628     if (hObj) hObj = GlobalReAlloc16( hObj,
629                      sizeof(CURSORICONINFO) + sizeXor + sizeAnd, GMEM_MOVEABLE );
630     if (!hObj) hObj = GlobalAlloc16( GMEM_MOVEABLE,
631                      sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
632     if (hObj)
633     {
634         CURSORICONINFO *info;
635
636         /* Make it owned by the module */
637         if (hInstance) hInstance = GetExePtr(hInstance);
638         FarSetOwner16( hObj, hInstance );
639
640         info = (CURSORICONINFO *)GlobalLock16( hObj );
641         info->ptHotSpot.x   = hotspot.x;
642         info->ptHotSpot.y   = hotspot.y;
643         info->nWidth        = bmpXor.bmWidth;
644         info->nHeight       = bmpXor.bmHeight;
645         info->nWidthBytes   = bmpXor.bmWidthBytes;
646         info->bPlanes       = bmpXor.bmPlanes;
647         info->bBitsPerPixel = bmpXor.bmBitsPixel;
648
649         /* Transfer the bitmap bits to the CURSORICONINFO structure */
650
651         GetBitmapBits( hAndBits, sizeAnd, (char *)(info + 1) );
652         GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
653         GlobalUnlock16( hObj );
654     }
655
656     DeleteObject( hAndBits );
657     DeleteObject( hXorBits );
658     return hObj;
659 }
660
661
662 /**********************************************************************
663  *              CreateIconFromResourceEx (USER.450)
664  *
665  * FIXME: not sure about exact parameter types
666  */
667 HICON16 WINAPI CreateIconFromResourceEx16( LPBYTE bits, UINT16 cbSize, BOOL16 bIcon,
668                                     DWORD dwVersion, INT16 width, INT16 height, UINT16 cFlag )
669 {
670     return CreateIconFromResourceEx(bits, cbSize, bIcon, dwVersion,
671       width, height, cFlag);
672 }
673
674
675 /**********************************************************************
676  *              CreateIconFromResource (USER32.@)
677  */
678 HICON WINAPI CreateIconFromResource( LPBYTE bits, UINT cbSize,
679                                            BOOL bIcon, DWORD dwVersion)
680 {
681     return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
682 }
683
684
685 /**********************************************************************
686  *              CreateIconFromResourceEx (USER32.@)
687  */
688 HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
689                                            BOOL bIcon, DWORD dwVersion,
690                                            INT width, INT height,
691                                            UINT cFlag )
692 {
693     return CURSORICON_CreateFromResource( 0, 0, bits, cbSize, bIcon, dwVersion,
694                                           width, height, cFlag );
695 }
696
697 /**********************************************************************
698  *          CURSORICON_Load
699  *
700  * Load a cursor or icon from resource or file.
701  */
702 HGLOBAL CURSORICON_Load( HINSTANCE hInstance, LPCWSTR name,
703                          INT width, INT height, INT colors,
704                          BOOL fCursor, UINT loadflags )
705 {
706     HANDLE handle = 0, h = 0;
707     HANDLE hRsrc;
708     CURSORICONDIR *dir;
709     CURSORICONDIRENTRY *dirEntry;
710     LPBYTE bits;
711
712     if ( loadflags & LR_LOADFROMFILE )    /* Load from file */
713     {
714         LPBYTE *ptr;
715         if (!CURSORICON_SimulateLoadingFromResourceW((LPWSTR)name, fCursor, &dir, &ptr))
716             return 0;
717         if (fCursor)
718             dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(dir, width, height, 1);
719         else
720             dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(dir, width, height, colors);
721         bits = ptr[dirEntry->wResId-1];
722         h = CURSORICON_CreateFromResource( 0, 0, bits, dirEntry->dwBytesInRes,
723                                            !fCursor, 0x00030000, width, height, loadflags);
724         HeapFree( GetProcessHeap(), 0, dir );
725         HeapFree( GetProcessHeap(), 0, ptr );
726     }
727     else  /* Load from resource */
728     {
729         HANDLE hGroupRsrc;
730         WORD wResId;
731         DWORD dwBytesInRes;
732
733         if (!hInstance)  /* Load OEM cursor/icon */
734         {
735             if (!(hInstance = GetModuleHandleA( "user32.dll" ))) return 0;
736         }
737
738         /* Normalize hInstance (must be uniquely represented for icon cache) */
739
740         if ( HIWORD( hInstance ) )
741             hInstance = MapHModuleLS( hInstance );
742         else
743             hInstance = GetExePtr( hInstance );
744
745         /* Get directory resource ID */
746
747         if (!(hRsrc = FindResourceW( hInstance, name,
748                           fCursor ? RT_GROUP_CURSORW : RT_GROUP_ICONW )))
749             return 0;
750         hGroupRsrc = hRsrc;
751
752         /* Find the best entry in the directory */
753
754         if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
755         if (!(dir = (CURSORICONDIR*)LockResource( handle ))) return 0;
756         if (fCursor)
757             dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor( dir,
758                                                               width, height, 1);
759         else
760             dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon( dir,
761                                                        width, height, colors );
762         if (!dirEntry) return 0;
763         wResId = dirEntry->wResId;
764         dwBytesInRes = dirEntry->dwBytesInRes;
765         FreeResource( handle );
766
767         /* Load the resource */
768
769         if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
770                                       fCursor ? RT_CURSORW : RT_ICONW ))) return 0;
771
772         /* If shared icon, check whether it was already loaded */
773         if (    (loadflags & LR_SHARED)
774              && (h = CURSORICON_FindSharedIcon( hInstance, hRsrc ) ) != 0 )
775             return h;
776
777         if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
778         bits = (LPBYTE)LockResource( handle );
779         h = CURSORICON_CreateFromResource( 0, 0, bits, dwBytesInRes,
780                                            !fCursor, 0x00030000, width, height, loadflags);
781         FreeResource( handle );
782
783         /* If shared icon, add to icon cache */
784
785         if ( h && (loadflags & LR_SHARED) )
786             CURSORICON_AddSharedIcon( hInstance, hRsrc, hGroupRsrc, h );
787     }
788
789     return h;
790 }
791
792 /***********************************************************************
793  *           CURSORICON_Copy
794  *
795  * Make a copy of a cursor or icon.
796  */
797 static HGLOBAL16 CURSORICON_Copy( HINSTANCE16 hInstance, HGLOBAL16 handle )
798 {
799     char *ptrOld, *ptrNew;
800     int size;
801     HGLOBAL16 hNew;
802
803     if (!(ptrOld = (char *)GlobalLock16( handle ))) return 0;
804     if (hInstance && !(hInstance = GetExePtr( hInstance ))) return 0;
805     size = GlobalSize16( handle );
806     hNew = GlobalAlloc16( GMEM_MOVEABLE, size );
807     FarSetOwner16( hNew, hInstance );
808     ptrNew = (char *)GlobalLock16( hNew );
809     memcpy( ptrNew, ptrOld, size );
810     GlobalUnlock16( handle );
811     GlobalUnlock16( hNew );
812     return hNew;
813 }
814
815 /*************************************************************************
816  * CURSORICON_ExtCopy
817  *
818  * Copies an Image from the Cache if LR_COPYFROMRESOURCE is specified
819  *
820  * PARAMS
821  *      Handle     [I] handle to an Image
822  *      nType      [I] Type of Handle (IMAGE_CURSOR | IMAGE_ICON)
823  *      iDesiredCX [I] The Desired width of the Image
824  *      iDesiredCY [I] The desired height of the Image
825  *      nFlags     [I] The flags from CopyImage
826  *
827  * RETURNS
828  *     Success: The new handle of the Image
829  *
830  * NOTES
831  *     LR_COPYDELETEORG and LR_MONOCHROME are currently not implemented.
832  *     LR_MONOCHROME should be implemented by CURSORICON_CreateFromResource.
833  *     LR_COPYFROMRESOURCE will only work if the Image is in the Cache.
834  *
835  *
836  */
837
838 HGLOBAL CURSORICON_ExtCopy(HGLOBAL Handle, UINT nType,
839                            INT iDesiredCX, INT iDesiredCY,
840                            UINT nFlags)
841 {
842     HGLOBAL16 hNew=0;
843
844     TRACE_(icon)("Handle %u, uType %u, iDesiredCX %i, iDesiredCY %i, nFlags %u\n",
845         Handle, nType, iDesiredCX, iDesiredCY, nFlags);
846
847     if(Handle == 0)
848     {
849         return 0;
850     }
851
852     /* Best Fit or Monochrome */
853     if( (nFlags & LR_COPYFROMRESOURCE
854         && (iDesiredCX > 0 || iDesiredCY > 0))
855         || nFlags & LR_MONOCHROME)
856     {
857         ICONCACHE* pIconCache = CURSORICON_FindCache(Handle);
858
859         /* Not Found in Cache, then do a straight copy
860         */
861         if(pIconCache == NULL)
862         {
863             hNew = CURSORICON_Copy(0, Handle);
864             if(nFlags & LR_COPYFROMRESOURCE)
865             {
866                 TRACE_(icon)("LR_COPYFROMRESOURCE: Failed to load from cache\n");
867             }
868         }
869         else
870         {
871             int iTargetCY = iDesiredCY, iTargetCX = iDesiredCX;
872             LPBYTE pBits;
873             HANDLE hMem;
874             HRSRC hRsrc;
875             DWORD dwBytesInRes;
876             WORD wResId;
877             CURSORICONDIR *pDir;
878             CURSORICONDIRENTRY *pDirEntry;
879             BOOL bIsIcon = (nType == IMAGE_ICON);
880
881             /* Completing iDesiredCX CY for Monochrome Bitmaps if needed
882             */
883             if(((nFlags & LR_MONOCHROME) && !(nFlags & LR_COPYFROMRESOURCE))
884                 || (iDesiredCX == 0 && iDesiredCY == 0))
885             {
886                 iDesiredCY = GetSystemMetrics(bIsIcon ?
887                     SM_CYICON : SM_CYCURSOR);
888                 iDesiredCX = GetSystemMetrics(bIsIcon ?
889                     SM_CXICON : SM_CXCURSOR);
890             }
891
892             /* Retrieve the CURSORICONDIRENTRY
893             */
894             if (!(hMem = LoadResource( pIconCache->hModule ,
895                             pIconCache->hGroupRsrc)))
896             {
897                 return 0;
898             }
899             if (!(pDir = (CURSORICONDIR*)LockResource( hMem )))
900             {
901                 return 0;
902             }
903
904             /* Find Best Fit
905             */
906             if(bIsIcon)
907             {
908                 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(
909                                 pDir, iDesiredCX, iDesiredCY, 256);
910             }
911             else
912             {
913                 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(
914                                 pDir, iDesiredCX, iDesiredCY, 1);
915             }
916
917             wResId = pDirEntry->wResId;
918             dwBytesInRes = pDirEntry->dwBytesInRes;
919             FreeResource(hMem);
920
921             TRACE_(icon)("ResID %u, BytesInRes %lu, Width %d, Height %d DX %d, DY %d\n",
922                 wResId, dwBytesInRes,  pDirEntry->ResInfo.icon.bWidth,
923                 pDirEntry->ResInfo.icon.bHeight, iDesiredCX, iDesiredCY);
924
925             /* Get the Best Fit
926             */
927             if (!(hRsrc = FindResourceW(pIconCache->hModule ,
928                 MAKEINTRESOURCEW(wResId), bIsIcon ? RT_ICONW : RT_CURSORW)))
929             {
930                 return 0;
931             }
932             if (!(hMem = LoadResource( pIconCache->hModule , hRsrc )))
933             {
934                 return 0;
935             }
936
937             pBits = (LPBYTE)LockResource( hMem );
938
939             if(nFlags & LR_DEFAULTSIZE)
940             {
941                 iTargetCY = GetSystemMetrics(SM_CYICON);
942                 iTargetCX = GetSystemMetrics(SM_CXICON);
943             }
944
945             /* Create a New Icon with the proper dimension
946             */
947             hNew = CURSORICON_CreateFromResource( 0, 0, pBits, dwBytesInRes,
948                        bIsIcon, 0x00030000, iTargetCX, iTargetCY, nFlags);
949             FreeResource(hMem);
950         }
951     }
952     else hNew = CURSORICON_Copy(0, Handle);
953     return hNew;
954 }
955
956
957 /***********************************************************************
958  *              LoadCursor (USER.173)
959  */
960 HCURSOR16 WINAPI LoadCursor16( HINSTANCE16 hInstance, LPCSTR name )
961 {
962     return LoadCursorA( hInstance, name );
963 }
964
965
966 /***********************************************************************
967  *              LoadIcon (USER.174)
968  */
969 HICON16 WINAPI LoadIcon16( HINSTANCE16 hInstance, LPCSTR name )
970 {
971     return LoadIconA( hInstance, name );
972 }
973
974
975 /***********************************************************************
976  *              CreateCursor (USER.406)
977  */
978 HCURSOR16 WINAPI CreateCursor16( HINSTANCE16 hInstance,
979                                  INT16 xHotSpot, INT16 yHotSpot,
980                                  INT16 nWidth, INT16 nHeight,
981                                  LPCVOID lpANDbits, LPCVOID lpXORbits )
982 {
983     CURSORICONINFO info;
984
985     TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
986                     nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
987
988     info.ptHotSpot.x = xHotSpot;
989     info.ptHotSpot.y = yHotSpot;
990     info.nWidth = nWidth;
991     info.nHeight = nHeight;
992     info.nWidthBytes = 0;
993     info.bPlanes = 1;
994     info.bBitsPerPixel = 1;
995
996     return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
997 }
998
999
1000 /***********************************************************************
1001  *              CreateCursor (USER32.@)
1002  */
1003 HCURSOR WINAPI CreateCursor( HINSTANCE hInstance,
1004                                  INT xHotSpot, INT yHotSpot,
1005                                  INT nWidth, INT nHeight,
1006                                  LPCVOID lpANDbits, LPCVOID lpXORbits )
1007 {
1008     CURSORICONINFO info;
1009
1010     TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1011                     nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1012
1013     info.ptHotSpot.x = xHotSpot;
1014     info.ptHotSpot.y = yHotSpot;
1015     info.nWidth = nWidth;
1016     info.nHeight = nHeight;
1017     info.nWidthBytes = 0;
1018     info.bPlanes = 1;
1019     info.bBitsPerPixel = 1;
1020
1021     return CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
1022 }
1023
1024
1025 /***********************************************************************
1026  *              CreateIcon (USER.407)
1027  */
1028 HICON16 WINAPI CreateIcon16( HINSTANCE16 hInstance, INT16 nWidth,
1029                              INT16 nHeight, BYTE bPlanes, BYTE bBitsPixel,
1030                              LPCVOID lpANDbits, LPCVOID lpXORbits )
1031 {
1032     CURSORICONINFO info;
1033
1034     TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1035                   nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1036
1037     info.ptHotSpot.x = ICON_HOTSPOT;
1038     info.ptHotSpot.y = ICON_HOTSPOT;
1039     info.nWidth = nWidth;
1040     info.nHeight = nHeight;
1041     info.nWidthBytes = 0;
1042     info.bPlanes = bPlanes;
1043     info.bBitsPerPixel = bBitsPixel;
1044
1045     return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1046 }
1047
1048
1049 /***********************************************************************
1050  *              CreateIcon (USER32.@)
1051  *
1052  *  Creates an icon based on the specified bitmaps. The bitmaps must be
1053  *  provided in a device dependent format and will be resized to
1054  *  (SM_CXICON,SM_CYICON) and depth converted to match the screen's color
1055  *  depth. The provided bitmaps must be top-down bitmaps.
1056  *  Although Windows does not support 15bpp(*) this API must support it
1057  *  for Winelib applications.
1058  *
1059  *  (*) Windows does not support 15bpp but it supports the 555 RGB 16bpp
1060  *      format!
1061  *
1062  * BUGS
1063  *
1064  *  - The provided bitmaps are not resized!
1065  *  - The documentation says the lpXORbits bitmap must be in a device
1066  *    dependent format. But we must still resize it and perform depth
1067  *    conversions if necessary.
1068  *  - I'm a bit unsure about the how the 'device dependent format' thing works.
1069  *    I did some tests on windows and found that if you provide a 16bpp bitmap
1070  *    in lpXORbits, then its format but be 565 RGB if the screen's bit depth
1071  *    is 16bpp but it must be 555 RGB if the screen's bit depth is anything
1072  *    else. I don't know if this is part of the GDI specs or if this is a
1073  *    quirk of the graphics card driver.
1074  *  - You may think that we check whether the bit depths match or not
1075  *    as an optimization. But the truth is that the conversion using
1076  *    CreateDIBitmap does not work for some bit depth (e.g. 8bpp) and I have
1077  *    no idea why.
1078  *  - I'm pretty sure that all the things we do in CreateIcon should
1079  *    also be done in CreateIconIndirect...
1080  */
1081 HICON WINAPI CreateIcon(
1082     HINSTANCE hInstance,  /* [in] the application's hInstance, currently unused */
1083     INT       nWidth,     /* [in] the width of the provided bitmaps */
1084     INT       nHeight,    /* [in] the height of the provided bitmaps */
1085     BYTE      bPlanes,    /* [in] the number of planes in the provided bitmaps */
1086     BYTE      bBitsPixel, /* [in] the number of bits per pixel of the lpXORbits bitmap */
1087     LPCVOID   lpANDbits,  /* [in] a monochrome bitmap representing the icon's mask */
1088     LPCVOID   lpXORbits)  /* [in] the icon's 'color' bitmap */
1089 {
1090     HICON hIcon;
1091     HDC hdc;
1092
1093     TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1094                  nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1095
1096     hdc=GetDC(0);
1097     if (!hdc)
1098         return 0;
1099
1100     if (GetDeviceCaps(hdc,BITSPIXEL)==bBitsPixel) {
1101         CURSORICONINFO info;
1102
1103         info.ptHotSpot.x = ICON_HOTSPOT;
1104         info.ptHotSpot.y = ICON_HOTSPOT;
1105         info.nWidth = nWidth;
1106         info.nHeight = nHeight;
1107         info.nWidthBytes = 0;
1108         info.bPlanes = bPlanes;
1109         info.bBitsPerPixel = bBitsPixel;
1110
1111         hIcon=CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
1112     } else {
1113         ICONINFO iinfo;
1114         BITMAPINFO bmi;
1115
1116         iinfo.fIcon=TRUE;
1117         iinfo.xHotspot=ICON_HOTSPOT;
1118         iinfo.yHotspot=ICON_HOTSPOT;
1119         iinfo.hbmMask=CreateBitmap(nWidth,nHeight,1,1,lpANDbits);
1120
1121         bmi.bmiHeader.biSize=sizeof(bmi.bmiHeader);
1122         bmi.bmiHeader.biWidth=nWidth;
1123         bmi.bmiHeader.biHeight=-nHeight;
1124         bmi.bmiHeader.biPlanes=bPlanes;
1125         bmi.bmiHeader.biBitCount=bBitsPixel;
1126         bmi.bmiHeader.biCompression=BI_RGB;
1127         bmi.bmiHeader.biSizeImage=0;
1128         bmi.bmiHeader.biXPelsPerMeter=0;
1129         bmi.bmiHeader.biYPelsPerMeter=0;
1130         bmi.bmiHeader.biClrUsed=0;
1131         bmi.bmiHeader.biClrImportant=0;
1132
1133         iinfo.hbmColor = CreateDIBitmap( hdc, &bmi.bmiHeader,
1134                                          CBM_INIT, lpXORbits,
1135                                          &bmi, DIB_RGB_COLORS );
1136
1137         hIcon=CreateIconIndirect(&iinfo);
1138         DeleteObject(iinfo.hbmMask);
1139         DeleteObject(iinfo.hbmColor);
1140     }
1141     ReleaseDC(0,hdc);
1142     return hIcon;
1143 }
1144
1145
1146 /***********************************************************************
1147  *              CreateCursorIconIndirect (USER.408)
1148  */
1149 HGLOBAL16 WINAPI CreateCursorIconIndirect16( HINSTANCE16 hInstance,
1150                                            CURSORICONINFO *info,
1151                                            LPCVOID lpANDbits,
1152                                            LPCVOID lpXORbits )
1153 {
1154     HGLOBAL16 handle;
1155     char *ptr;
1156     int sizeAnd, sizeXor;
1157
1158     hInstance = GetExePtr( hInstance );  /* Make it a module handle */
1159     if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
1160     info->nWidthBytes = BITMAP_GetWidthBytes(info->nWidth,info->bBitsPerPixel);
1161     sizeXor = info->nHeight * info->nWidthBytes;
1162     sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
1163     if (!(handle = GlobalAlloc16( GMEM_MOVEABLE,
1164                                   sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
1165         return 0;
1166     FarSetOwner16( handle, hInstance );
1167     ptr = (char *)GlobalLock16( handle );
1168     memcpy( ptr, info, sizeof(*info) );
1169     memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
1170     memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
1171     GlobalUnlock16( handle );
1172     return handle;
1173 }
1174
1175
1176 /***********************************************************************
1177  *              CopyIcon (USER.368)
1178  */
1179 HICON16 WINAPI CopyIcon16( HINSTANCE16 hInstance, HICON16 hIcon )
1180 {
1181     TRACE_(icon)("%04x %04x\n", hInstance, hIcon );
1182     return CURSORICON_Copy( hInstance, hIcon );
1183 }
1184
1185
1186 /***********************************************************************
1187  *              CopyIcon (USER32.@)
1188  */
1189 HICON WINAPI CopyIcon( HICON hIcon )
1190 {
1191     TRACE_(icon)("%04x\n", hIcon );
1192     return CURSORICON_Copy( 0, hIcon );
1193 }
1194
1195
1196 /***********************************************************************
1197  *              CopyCursor (USER.369)
1198  */
1199 HCURSOR16 WINAPI CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
1200 {
1201     TRACE_(cursor)("%04x %04x\n", hInstance, hCursor );
1202     return CURSORICON_Copy( hInstance, hCursor );
1203 }
1204
1205 /**********************************************************************
1206  *              DestroyIcon32 (USER.610)
1207  *              DestroyIcon32 (USER32.@)
1208  *
1209  * This routine is actually exported from Win95 USER under the name
1210  * DestroyIcon32 ...  The behaviour implemented here should mimic
1211  * the Win95 one exactly, especially the return values, which
1212  * depend on the setting of various flags.
1213  */
1214 WORD WINAPI DestroyIcon32( HGLOBAL16 handle, UINT16 flags )
1215 {
1216     WORD retv;
1217
1218     TRACE_(icon)("(%04x, %04x)\n", handle, flags );
1219
1220     /* Check whether destroying active cursor */
1221
1222     if ( QUEUE_Current()->cursor == handle )
1223     {
1224         WARN_(cursor)("Destroying active cursor!\n" );
1225         SetCursor( 0 );
1226     }
1227
1228     /* Try shared cursor/icon first */
1229
1230     if ( !(flags & CID_NONSHARED) )
1231     {
1232         INT count = CURSORICON_DelSharedIcon( handle );
1233
1234         if ( count != -1 )
1235             return (flags & CID_WIN32)? TRUE : (count == 0);
1236
1237         /* FIXME: OEM cursors/icons should be recognized */
1238     }
1239
1240     /* Now assume non-shared cursor/icon */
1241
1242     retv = GlobalFree16( handle );
1243     return (flags & CID_RESOURCE)? retv : TRUE;
1244 }
1245
1246 /***********************************************************************
1247  *              DestroyIcon (USER.457)
1248  */
1249 BOOL16 WINAPI DestroyIcon16( HICON16 hIcon )
1250 {
1251     return DestroyIcon32( hIcon, 0 );
1252 }
1253
1254 /***********************************************************************
1255  *              DestroyIcon (USER32.@)
1256  */
1257 BOOL WINAPI DestroyIcon( HICON hIcon )
1258 {
1259     return DestroyIcon32( hIcon, CID_WIN32 );
1260 }
1261
1262 /***********************************************************************
1263  *              DestroyCursor (USER.458)
1264  */
1265 BOOL16 WINAPI DestroyCursor16( HCURSOR16 hCursor )
1266 {
1267     return DestroyIcon32( hCursor, 0 );
1268 }
1269
1270 /***********************************************************************
1271  *              DestroyCursor (USER32.@)
1272  */
1273 BOOL WINAPI DestroyCursor( HCURSOR hCursor )
1274 {
1275     return DestroyIcon32( hCursor, CID_WIN32 );
1276 }
1277
1278
1279 /***********************************************************************
1280  *              DrawIcon (USER.84)
1281  */
1282 BOOL16 WINAPI DrawIcon16( HDC16 hdc, INT16 x, INT16 y, HICON16 hIcon )
1283 {
1284     return DrawIcon( hdc, x, y, hIcon );
1285 }
1286
1287
1288 /***********************************************************************
1289  *              DrawIcon (USER32.@)
1290  */
1291 BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
1292 {
1293     CURSORICONINFO *ptr;
1294     HDC hMemDC;
1295     HBITMAP hXorBits, hAndBits;
1296     COLORREF oldFg, oldBg;
1297
1298     if (!(ptr = (CURSORICONINFO *)GlobalLock16( hIcon ))) return FALSE;
1299     if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
1300     hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1,
1301                                (char *)(ptr+1) );
1302     hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
1303                                ptr->bBitsPerPixel, (char *)(ptr + 1)
1304                         + ptr->nHeight * BITMAP_GetWidthBytes(ptr->nWidth,1) );
1305     oldFg = SetTextColor( hdc, RGB(0,0,0) );
1306     oldBg = SetBkColor( hdc, RGB(255,255,255) );
1307
1308     if (hXorBits && hAndBits)
1309     {
1310         HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1311         BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
1312         SelectObject( hMemDC, hXorBits );
1313         BitBlt(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
1314         SelectObject( hMemDC, hBitTemp );
1315     }
1316     DeleteDC( hMemDC );
1317     if (hXorBits) DeleteObject( hXorBits );
1318     if (hAndBits) DeleteObject( hAndBits );
1319     GlobalUnlock16( hIcon );
1320     SetTextColor( hdc, oldFg );
1321     SetBkColor( hdc, oldBg );
1322     return TRUE;
1323 }
1324
1325
1326 /***********************************************************************
1327  *              IconSize (USER.86)
1328  *
1329  * See "Undocumented Windows". Used by W2.0 paint.exe.
1330  */
1331 DWORD WINAPI IconSize16( void )
1332 {
1333     return MAKELONG(GetSystemMetrics(SM_CYICON), GetSystemMetrics(SM_CXICON));
1334 }
1335
1336
1337 /***********************************************************************
1338  *              DumpIcon (USER.459)
1339  */
1340 DWORD WINAPI DumpIcon16( SEGPTR pInfo, WORD *lpLen,
1341                        SEGPTR *lpXorBits, SEGPTR *lpAndBits )
1342 {
1343     CURSORICONINFO *info = MapSL( pInfo );
1344     int sizeAnd, sizeXor;
1345
1346     if (!info) return 0;
1347     sizeXor = info->nHeight * info->nWidthBytes;
1348     sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
1349     if (lpAndBits) *lpAndBits = pInfo + sizeof(CURSORICONINFO);
1350     if (lpXorBits) *lpXorBits = pInfo + sizeof(CURSORICONINFO) + sizeAnd;
1351     if (lpLen) *lpLen = sizeof(CURSORICONINFO) + sizeAnd + sizeXor;
1352     return MAKELONG( sizeXor, sizeXor );
1353 }
1354
1355
1356 /***********************************************************************
1357  *              SetCursor (USER.69)
1358  */
1359 HCURSOR16 WINAPI SetCursor16( HCURSOR16 hCursor )
1360 {
1361     return (HCURSOR16)SetCursor( hCursor );
1362 }
1363
1364
1365 /***********************************************************************
1366  *              SetCursor (USER32.@)
1367  * RETURNS:
1368  *      A handle to the previous cursor shape.
1369  */
1370 HCURSOR WINAPI SetCursor( HCURSOR hCursor /* [in] Handle of cursor to show */ )
1371 {
1372     MESSAGEQUEUE *queue = QUEUE_Current();
1373     HCURSOR hOldCursor;
1374
1375     if (hCursor == queue->cursor) return hCursor;  /* No change */
1376     TRACE_(cursor)("%04x\n", hCursor );
1377     hOldCursor = queue->cursor;
1378     queue->cursor = hCursor;
1379     /* Change the cursor shape only if it is visible */
1380     if (queue->cursor_count >= 0)
1381     {
1382         USER_Driver.pSetCursor( (CURSORICONINFO*)GlobalLock16( hCursor ) );
1383         GlobalUnlock16( hCursor );
1384     }
1385     return hOldCursor;
1386 }
1387
1388
1389 /***********************************************************************
1390  *              ShowCursor (USER.71)
1391  */
1392 INT16 WINAPI ShowCursor16( BOOL16 bShow )
1393 {
1394     return ShowCursor( bShow );
1395 }
1396
1397
1398 /***********************************************************************
1399  *              ShowCursor (USER32.@)
1400  */
1401 INT WINAPI ShowCursor( BOOL bShow )
1402 {
1403     MESSAGEQUEUE *queue = QUEUE_Current();
1404
1405     TRACE_(cursor)("%d, count=%d\n", bShow, queue->cursor_count );
1406
1407     if (bShow)
1408     {
1409         if (++queue->cursor_count == 0)  /* Show it */
1410         {
1411             USER_Driver.pSetCursor( (CURSORICONINFO*)GlobalLock16( queue->cursor ) );
1412             GlobalUnlock16( queue->cursor );
1413         }
1414     }
1415     else
1416     {
1417         if (--queue->cursor_count == -1)  /* Hide it */
1418             USER_Driver.pSetCursor( NULL );
1419     }
1420     return queue->cursor_count;
1421 }
1422
1423
1424 /***********************************************************************
1425  *              GetCursor (USER.247)
1426  */
1427 HCURSOR16 WINAPI GetCursor16(void)
1428 {
1429     return GetCursor();
1430 }
1431
1432
1433 /***********************************************************************
1434  *              GetCursor (USER32.@)
1435  */
1436 HCURSOR WINAPI GetCursor(void)
1437 {
1438     return QUEUE_Current()->cursor;
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 }