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