user32: Reimplement CopyIcon16/CopyCursor16 using CreateCursorIconIndirect16.
[wine] / dlls / user32 / 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  *           2007 Henri Verbeet
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24
25 /*
26  * Theory:
27  *
28  * Cursors and icons are stored in a global heap block, with the
29  * following layout:
30  *
31  * CURSORICONINFO info;
32  * BYTE[]         ANDbits;
33  * BYTE[]         XORbits;
34  *
35  * The bits structures are in the format of a device-dependent bitmap.
36  *
37  * This layout is very sub-optimal, as the bitmap bits are stored in
38  * the X client instead of in the server like other bitmaps; however,
39  * some programs (notably Paint Brush) expect to be able to manipulate
40  * the bits directly :-(
41  */
42
43 #include "config.h"
44 #include "wine/port.h"
45
46 #include <stdarg.h>
47 #include <string.h>
48 #include <stdlib.h>
49
50 #include "windef.h"
51 #include "winbase.h"
52 #include "wingdi.h"
53 #include "winerror.h"
54 #include "wine/winbase16.h"
55 #include "wine/winuser16.h"
56 #include "wine/exception.h"
57 #include "wine/debug.h"
58 #include "user_private.h"
59
60 WINE_DEFAULT_DEBUG_CHANNEL(cursor);
61 WINE_DECLARE_DEBUG_CHANNEL(icon);
62 WINE_DECLARE_DEBUG_CHANNEL(resource);
63
64 #include "pshpack1.h"
65
66 typedef struct {
67     BYTE bWidth;
68     BYTE bHeight;
69     BYTE bColorCount;
70     BYTE bReserved;
71     WORD xHotspot;
72     WORD yHotspot;
73     DWORD dwDIBSize;
74     DWORD dwDIBOffset;
75 } CURSORICONFILEDIRENTRY;
76
77 typedef struct
78 {
79     WORD                idReserved;
80     WORD                idType;
81     WORD                idCount;
82     CURSORICONFILEDIRENTRY  idEntries[1];
83 } CURSORICONFILEDIR;
84
85 #include "poppack.h"
86
87 #define CID_RESOURCE  0x0001
88 #define CID_WIN32     0x0004
89 #define CID_NONSHARED 0x0008
90
91 static RECT CURSOR_ClipRect;       /* Cursor clipping rect */
92
93 static HDC screen_dc;
94
95 static const WCHAR DISPLAYW[] = {'D','I','S','P','L','A','Y',0};
96
97 /**********************************************************************
98  * ICONCACHE for cursors/icons loaded with LR_SHARED.
99  *
100  * FIXME: This should not be allocated on the system heap, but on a
101  *        subsystem-global heap (i.e. one for all Win16 processes,
102  *        and one for each Win32 process).
103  */
104 typedef struct tagICONCACHE
105 {
106     struct tagICONCACHE *next;
107
108     HMODULE              hModule;
109     HRSRC                hRsrc;
110     HRSRC                hGroupRsrc;
111     HICON                hIcon;
112
113     INT                  count;
114
115 } ICONCACHE;
116
117 static ICONCACHE *IconAnchor = NULL;
118
119 static CRITICAL_SECTION IconCrst;
120 static CRITICAL_SECTION_DEBUG critsect_debug =
121 {
122     0, 0, &IconCrst,
123     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
124       0, 0, { (DWORD_PTR)(__FILE__ ": IconCrst") }
125 };
126 static CRITICAL_SECTION IconCrst = { &critsect_debug, -1, 0, 0, 0, 0 };
127
128 static const WORD ICON_HOTSPOT = 0x4242;
129
130
131 /***********************************************************************
132  *             map_fileW
133  *
134  * Helper function to map a file to memory:
135  *  name                        -       file name
136  *  [RETURN] ptr                -       pointer to mapped file
137  *  [RETURN] filesize           -       pointer size of file to be stored if not NULL
138  */
139 static void *map_fileW( LPCWSTR name, LPDWORD filesize )
140 {
141     HANDLE hFile, hMapping;
142     LPVOID ptr = NULL;
143
144     hFile = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL,
145                          OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0 );
146     if (hFile != INVALID_HANDLE_VALUE)
147     {
148         hMapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
149         if (hMapping)
150         {
151             ptr = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
152             CloseHandle( hMapping );
153             if (filesize)
154                 *filesize = GetFileSize( hFile, NULL );
155         }
156         CloseHandle( hFile );
157     }
158     return ptr;
159 }
160
161
162 /***********************************************************************
163  *           get_bitmap_width_bytes
164  *
165  * Return number of bytes taken by a scanline of 16-bit aligned Windows DDB
166  * data.
167  */
168 static int get_bitmap_width_bytes( int width, int bpp )
169 {
170     switch(bpp)
171     {
172     case 1:
173         return 2 * ((width+15) / 16);
174     case 4:
175         return 2 * ((width+3) / 4);
176     case 24:
177         width *= 3;
178         /* fall through */
179     case 8:
180         return width + (width & 1);
181     case 16:
182     case 15:
183         return width * 2;
184     case 32:
185         return width * 4;
186     default:
187         WARN("Unknown depth %d, please report.\n", bpp );
188     }
189     return -1;
190 }
191
192
193 /***********************************************************************
194  *          get_dib_width_bytes
195  *
196  * Return the width of a DIB bitmap in bytes. DIB bitmap data is 32-bit aligned.
197  */
198 static int get_dib_width_bytes( int width, int depth )
199 {
200     int words;
201
202     switch(depth)
203     {
204     case 1:  words = (width + 31) / 32; break;
205     case 4:  words = (width + 7) / 8; break;
206     case 8:  words = (width + 3) / 4; break;
207     case 15:
208     case 16: words = (width + 1) / 2; break;
209     case 24: words = (width * 3 + 3)/4; break;
210     default:
211         WARN("(%d): Unsupported depth\n", depth );
212         /* fall through */
213     case 32:
214         words = width;
215     }
216     return 4 * words;
217 }
218
219
220 /***********************************************************************
221  *           bitmap_info_size
222  *
223  * Return the size of the bitmap info structure including color table.
224  */
225 static int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
226 {
227     int colors, masks = 0;
228
229     if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
230     {
231         const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
232         colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
233         return sizeof(BITMAPCOREHEADER) + colors *
234              ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
235     }
236     else  /* assume BITMAPINFOHEADER */
237     {
238         colors = info->bmiHeader.biClrUsed;
239         if (colors > 256) /* buffer overflow otherwise */
240                 colors = 256;
241         if (!colors && (info->bmiHeader.biBitCount <= 8))
242             colors = 1 << info->bmiHeader.biBitCount;
243         if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
244         return sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) + colors *
245                ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
246     }
247 }
248
249
250 /***********************************************************************
251  *          is_dib_monochrome
252  *
253  * Returns whether a DIB can be converted to a monochrome DDB.
254  *
255  * A DIB can be converted if its color table contains only black and
256  * white. Black must be the first color in the color table.
257  *
258  * Note : If the first color in the color table is white followed by
259  *        black, we can't convert it to a monochrome DDB with
260  *        SetDIBits, because black and white would be inverted.
261  */
262 static BOOL is_dib_monochrome( const BITMAPINFO* info )
263 {
264     if (info->bmiHeader.biBitCount != 1) return FALSE;
265
266     if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
267     {
268         const RGBTRIPLE *rgb = ((const BITMAPCOREINFO*)info)->bmciColors;
269
270         /* Check if the first color is black */
271         if ((rgb->rgbtRed == 0) && (rgb->rgbtGreen == 0) && (rgb->rgbtBlue == 0))
272         {
273             rgb++;
274
275             /* Check if the second color is white */
276             return ((rgb->rgbtRed == 0xff) && (rgb->rgbtGreen == 0xff)
277                  && (rgb->rgbtBlue == 0xff));
278         }
279         else return FALSE;
280     }
281     else  /* assume BITMAPINFOHEADER */
282     {
283         const RGBQUAD *rgb = info->bmiColors;
284
285         /* Check if the first color is black */
286         if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) &&
287             (rgb->rgbBlue == 0) && (rgb->rgbReserved == 0))
288         {
289             rgb++;
290
291             /* Check if the second color is white */
292             return ((rgb->rgbRed == 0xff) && (rgb->rgbGreen == 0xff)
293                  && (rgb->rgbBlue == 0xff) && (rgb->rgbReserved == 0));
294         }
295         else return FALSE;
296     }
297 }
298
299 /***********************************************************************
300  *           DIB_GetBitmapInfo
301  *
302  * Get the info from a bitmap header.
303  * Return 1 for INFOHEADER, 0 for COREHEADER,
304  * 4 for V4HEADER, 5 for V5HEADER, -1 for error.
305  */
306 static int DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width,
307                               LONG *height, WORD *bpp, DWORD *compr )
308 {
309     if (header->biSize == sizeof(BITMAPINFOHEADER))
310     {
311         *width  = header->biWidth;
312         *height = header->biHeight;
313         *bpp    = header->biBitCount;
314         *compr  = header->biCompression;
315         return 1;
316     }
317     if (header->biSize == sizeof(BITMAPCOREHEADER))
318     {
319         const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header;
320         *width  = core->bcWidth;
321         *height = core->bcHeight;
322         *bpp    = core->bcBitCount;
323         *compr  = 0;
324         return 0;
325     }
326     if (header->biSize == sizeof(BITMAPV4HEADER))
327     {
328         const BITMAPV4HEADER *v4hdr = (const BITMAPV4HEADER *)header;
329         *width  = v4hdr->bV4Width;
330         *height = v4hdr->bV4Height;
331         *bpp    = v4hdr->bV4BitCount;
332         *compr  = v4hdr->bV4V4Compression;
333         return 4;
334     }
335     if (header->biSize == sizeof(BITMAPV5HEADER))
336     {
337         const BITMAPV5HEADER *v5hdr = (const BITMAPV5HEADER *)header;
338         *width  = v5hdr->bV5Width;
339         *height = v5hdr->bV5Height;
340         *bpp    = v5hdr->bV5BitCount;
341         *compr  = v5hdr->bV5Compression;
342         return 5;
343     }
344     ERR("(%d): unknown/wrong size for header\n", header->biSize );
345     return -1;
346 }
347
348 /**********************************************************************
349  *          CURSORICON_FindSharedIcon
350  */
351 static HICON CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
352 {
353     HICON hIcon = 0;
354     ICONCACHE *ptr;
355
356     EnterCriticalSection( &IconCrst );
357
358     for ( ptr = IconAnchor; ptr; ptr = ptr->next )
359         if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
360         {
361             ptr->count++;
362             hIcon = ptr->hIcon;
363             break;
364         }
365
366     LeaveCriticalSection( &IconCrst );
367
368     return hIcon;
369 }
370
371 /*************************************************************************
372  * CURSORICON_FindCache
373  *
374  * Given a handle, find the corresponding cache element
375  *
376  * PARAMS
377  *      Handle     [I] handle to an Image
378  *
379  * RETURNS
380  *     Success: The cache entry
381  *     Failure: NULL
382  *
383  */
384 static ICONCACHE* CURSORICON_FindCache(HICON hIcon)
385 {
386     ICONCACHE *ptr;
387     ICONCACHE *pRet=NULL;
388     BOOL IsFound = FALSE;
389
390     EnterCriticalSection( &IconCrst );
391
392     for (ptr = IconAnchor; ptr != NULL && !IsFound; ptr = ptr->next)
393     {
394         if ( hIcon == ptr->hIcon )
395         {
396             IsFound = TRUE;
397             pRet = ptr;
398         }
399     }
400
401     LeaveCriticalSection( &IconCrst );
402
403     return pRet;
404 }
405
406 /**********************************************************************
407  *          CURSORICON_AddSharedIcon
408  */
409 static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HRSRC hGroupRsrc, HICON hIcon )
410 {
411     ICONCACHE *ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(ICONCACHE) );
412     if ( !ptr ) return;
413
414     ptr->hModule = hModule;
415     ptr->hRsrc   = hRsrc;
416     ptr->hIcon  = hIcon;
417     ptr->hGroupRsrc = hGroupRsrc;
418     ptr->count   = 1;
419
420     EnterCriticalSection( &IconCrst );
421     ptr->next    = IconAnchor;
422     IconAnchor   = ptr;
423     LeaveCriticalSection( &IconCrst );
424 }
425
426 /**********************************************************************
427  *          CURSORICON_DelSharedIcon
428  */
429 static INT CURSORICON_DelSharedIcon( HICON hIcon )
430 {
431     INT count = -1;
432     ICONCACHE *ptr;
433
434     EnterCriticalSection( &IconCrst );
435
436     for ( ptr = IconAnchor; ptr; ptr = ptr->next )
437         if ( ptr->hIcon == hIcon )
438         {
439             if ( ptr->count > 0 ) ptr->count--;
440             count = ptr->count;
441             break;
442         }
443
444     LeaveCriticalSection( &IconCrst );
445
446     return count;
447 }
448
449 /**********************************************************************
450  *          CURSORICON_FreeModuleIcons
451  */
452 void CURSORICON_FreeModuleIcons( HMODULE16 hMod16 )
453 {
454     ICONCACHE **ptr = &IconAnchor;
455     HMODULE hModule = HMODULE_32(GetExePtr( hMod16 ));
456
457     EnterCriticalSection( &IconCrst );
458
459     while ( *ptr )
460     {
461         if ( (*ptr)->hModule == hModule )
462         {
463             ICONCACHE *freePtr = *ptr;
464             *ptr = freePtr->next;
465
466             GlobalFree16(HICON_16(freePtr->hIcon));
467             HeapFree( GetProcessHeap(), 0, freePtr );
468             continue;
469         }
470         ptr = &(*ptr)->next;
471     }
472
473     LeaveCriticalSection( &IconCrst );
474 }
475
476 /**********************************************************************
477  *              get_icon_size
478  */
479 BOOL get_icon_size( HICON handle, SIZE *size )
480 {
481     CURSORICONINFO *info;
482
483     if (!(info = GlobalLock16( HICON_16(handle) ))) return FALSE;
484     size->cx = info->nWidth;
485     size->cy = info->nHeight;
486     GlobalUnlock16( HICON_16(handle) );
487     return TRUE;
488 }
489
490 /*
491  *  The following macro functions account for the irregularities of
492  *   accessing cursor and icon resources in files and resource entries.
493  */
494 typedef BOOL (*fnGetCIEntry)( LPVOID dir, int n,
495                               int *width, int *height, int *bits );
496
497 /**********************************************************************
498  *          CURSORICON_FindBestIcon
499  *
500  * Find the icon closest to the requested size and number of colors.
501  */
502 static int CURSORICON_FindBestIcon( LPVOID dir, fnGetCIEntry get_entry,
503                                     int width, int height, int colors )
504 {
505     int i, cx, cy, bits, bestEntry = -1;
506     UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
507     UINT iTempXDiff, iTempYDiff, iTempColorDiff;
508
509     /* Find Best Fit */
510     iTotalDiff = 0xFFFFFFFF;
511     iColorDiff = 0xFFFFFFFF;
512     for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
513     {
514         iTempXDiff = abs(width - cx);
515         iTempYDiff = abs(height - cy);
516
517         if(iTotalDiff > (iTempXDiff + iTempYDiff))
518         {
519             iXDiff = iTempXDiff;
520             iYDiff = iTempYDiff;
521             iTotalDiff = iXDiff + iYDiff;
522         }
523     }
524
525     /* Find Best Colors for Best Fit */
526     for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
527     {
528         if(abs(width - cx) == iXDiff && abs(height - cy) == iYDiff)
529         {
530             iTempColorDiff = abs(colors - (1<<bits));
531             if(iColorDiff > iTempColorDiff)
532             {
533                 bestEntry = i;
534                 iColorDiff = iTempColorDiff;
535             }
536         }
537     }
538
539     return bestEntry;
540 }
541
542 static BOOL CURSORICON_GetResIconEntry( LPVOID dir, int n,
543                                         int *width, int *height, int *bits )
544 {
545     CURSORICONDIR *resdir = dir;
546     ICONRESDIR *icon;
547
548     if ( resdir->idCount <= n )
549         return FALSE;
550     icon = &resdir->idEntries[n].ResInfo.icon;
551     *width = icon->bWidth;
552     *height = icon->bHeight;
553     *bits = resdir->idEntries[n].wBitCount;
554     return TRUE;
555 }
556
557 /**********************************************************************
558  *          CURSORICON_FindBestCursor
559  *
560  * Find the cursor closest to the requested size.
561  *
562  * FIXME: parameter 'color' ignored.
563  */
564 static int CURSORICON_FindBestCursor( LPVOID dir, fnGetCIEntry get_entry,
565                                       int width, int height, int color )
566 {
567     int i, maxwidth, maxheight, cx, cy, bits, bestEntry = -1;
568
569     /* Double height to account for AND and XOR masks */
570
571     height *= 2;
572
573     /* First find the largest one smaller than or equal to the requested size*/
574
575     maxwidth = maxheight = 0;
576     for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
577     {
578         if ((cx <= width) && (cy <= height) &&
579             (cx > maxwidth) && (cy > maxheight))
580         {
581             bestEntry = i;
582             maxwidth  = cx;
583             maxheight = cy;
584         }
585     }
586     if (bestEntry != -1) return bestEntry;
587
588     /* Now find the smallest one larger than the requested size */
589
590     maxwidth = maxheight = 255;
591     for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
592     {
593         if (((cx < maxwidth) && (cy < maxheight)) || (bestEntry == -1))
594         {
595             bestEntry = i;
596             maxwidth  = cx;
597             maxheight = cy;
598         }
599     }
600
601     return bestEntry;
602 }
603
604 static BOOL CURSORICON_GetResCursorEntry( LPVOID dir, int n,
605                                           int *width, int *height, int *bits )
606 {
607     CURSORICONDIR *resdir = dir;
608     CURSORDIR *cursor;
609
610     if ( resdir->idCount <= n )
611         return FALSE;
612     cursor = &resdir->idEntries[n].ResInfo.cursor;
613     *width = cursor->wWidth;
614     *height = cursor->wHeight;
615     *bits = resdir->idEntries[n].wBitCount;
616     return TRUE;
617 }
618
619 static CURSORICONDIRENTRY *CURSORICON_FindBestIconRes( CURSORICONDIR * dir,
620                                       int width, int height, int colors )
621 {
622     int n;
623
624     n = CURSORICON_FindBestIcon( dir, CURSORICON_GetResIconEntry,
625                                  width, height, colors );
626     if ( n < 0 )
627         return NULL;
628     return &dir->idEntries[n];
629 }
630
631 static CURSORICONDIRENTRY *CURSORICON_FindBestCursorRes( CURSORICONDIR *dir,
632                                       int width, int height, int color )
633 {
634     int n = CURSORICON_FindBestCursor( dir, CURSORICON_GetResCursorEntry,
635                                    width, height, color );
636     if ( n < 0 )
637         return NULL;
638     return &dir->idEntries[n];
639 }
640
641 static BOOL CURSORICON_GetFileEntry( LPVOID dir, int n,
642                                      int *width, int *height, int *bits )
643 {
644     CURSORICONFILEDIR *filedir = dir;
645     CURSORICONFILEDIRENTRY *entry;
646
647     if ( filedir->idCount <= n )
648         return FALSE;
649     entry = &filedir->idEntries[n];
650     *width = entry->bWidth;
651     *height = entry->bHeight;
652     *bits = entry->bColorCount;
653     return TRUE;
654 }
655
656 static CURSORICONFILEDIRENTRY *CURSORICON_FindBestCursorFile( CURSORICONFILEDIR *dir,
657                                       int width, int height, int color )
658 {
659     int n = CURSORICON_FindBestCursor( dir, CURSORICON_GetFileEntry,
660                                        width, height, color );
661     if ( n < 0 )
662         return NULL;
663     return &dir->idEntries[n];
664 }
665
666 static CURSORICONFILEDIRENTRY *CURSORICON_FindBestIconFile( CURSORICONFILEDIR *dir,
667                                       int width, int height, int color )
668 {
669     int n = CURSORICON_FindBestIcon( dir, CURSORICON_GetFileEntry,
670                                      width, height, color );
671     if ( n < 0 )
672         return NULL;
673     return &dir->idEntries[n];
674 }
675
676 /***********************************************************************
677  *          stretch_blt_icon
678  *
679  * A helper function that stretches a bitmap buffer into an HBITMAP.
680  *
681  * PARAMS
682  *      hDest       [I] The handle of the destination bitmap.
683  *      pDestInfo   [I] The BITMAPINFO of the destination bitmap.
684  *      pSrcInfo    [I] The BITMAPINFO of the source bitmap.
685  *      pSrcBits    [I] A pointer to the source bitmap buffer.
686  **/
687 static BOOL stretch_blt_icon(HBITMAP hDest, BITMAPINFO *pDestInfo, BITMAPINFO *pSrcInfo, char *pSrcBits)
688 {
689     HBITMAP hOld;
690     BOOL res = FALSE;
691     HDC hdcMem = CreateCompatibleDC(screen_dc);
692
693     if (hdcMem)
694     {
695         hOld = SelectObject(hdcMem, hDest);
696         res = StretchDIBits(hdcMem,
697                             0, 0, pDestInfo->bmiHeader.biWidth, pDestInfo->bmiHeader.biHeight,
698                             0, 0, pSrcInfo->bmiHeader.biWidth, pSrcInfo->bmiHeader.biHeight,
699                             pSrcBits, pSrcInfo, DIB_RGB_COLORS, SRCCOPY);
700         SelectObject(hdcMem, hOld);
701         DeleteDC( hdcMem );
702     }
703
704     return res;
705 }
706
707 static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
708                                            POINT16 hotspot, BOOL bIcon,
709                                            DWORD dwVersion,
710                                            INT width, INT height,
711                                            UINT cFlag )
712 {
713     HGLOBAL16 hObj;
714     int sizeAnd, sizeXor;
715     HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
716     BITMAP bmpXor, bmpAnd;
717     INT size;
718     BITMAPINFO *pSrcInfo, *pDestInfo;
719
720     if (dwVersion == 0x00020000)
721     {
722         FIXME_(cursor)("\t2.xx resources are not supported\n");
723         return 0;
724     }
725
726     /* Check bitmap header */
727
728     if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
729          (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)  ||
730           bmi->bmiHeader.biCompression != BI_RGB) )
731     {
732           WARN_(cursor)("\tinvalid resource bitmap header.\n");
733           return 0;
734     }
735
736     size = bitmap_info_size( bmi, DIB_RGB_COLORS );
737
738     if (!width) width = bmi->bmiHeader.biWidth;
739     if (!height) height = bmi->bmiHeader.biHeight/2;
740
741     /* Scale the hotspot */
742     if (((bmi->bmiHeader.biHeight/2 != height) || (bmi->bmiHeader.biWidth != width)) &&
743         hotspot.x != ICON_HOTSPOT && hotspot.y != ICON_HOTSPOT)
744     {
745         hotspot.x = (hotspot.x * width) / bmi->bmiHeader.biWidth;
746         hotspot.y = (hotspot.y * height) / (bmi->bmiHeader.biHeight / 2);
747     }
748
749     if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
750     if (screen_dc)
751     {
752         /* Make sure we have room for the monochrome bitmap later on.
753          * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
754          * up to and including the biBitCount. In-memory icon resource
755          * format is as follows:
756          *
757          *   BITMAPINFOHEADER   icHeader  // DIB header
758          *   RGBQUAD         icColors[]   // Color table
759          *   BYTE            icXOR[]      // DIB bits for XOR mask
760          *   BYTE            icAND[]      // DIB bits for AND mask
761          */
762
763         pSrcInfo = HeapAlloc( GetProcessHeap(), 0,
764                               max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)));
765         pDestInfo = HeapAlloc( GetProcessHeap(), 0,
766                               max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)));
767         if (pSrcInfo && pDestInfo)
768         {
769             memcpy( pSrcInfo, bmi, size );
770             pSrcInfo->bmiHeader.biHeight /= 2;
771
772             memcpy( pDestInfo, bmi, size );
773             pDestInfo->bmiHeader.biWidth = width;
774             pDestInfo->bmiHeader.biHeight = height;
775             pDestInfo->bmiHeader.biSizeImage = 0;
776
777             /* Create the XOR bitmap */
778             if(pSrcInfo->bmiHeader.biBitCount == 32)
779             {
780                 void *pDIBBuffer = NULL;
781                 hXorBits = CreateDIBSection(screen_dc, pDestInfo, DIB_RGB_COLORS, &pDIBBuffer, NULL, 0);
782
783                 if(hXorBits)
784                 {
785                     if (!stretch_blt_icon(hXorBits, pDestInfo, pSrcInfo, (char*)bmi + size))
786                     {
787                         DeleteObject(hXorBits);
788                         hXorBits = 0;
789                     }
790                 }
791             }
792             else
793             {
794                 hXorBits = CreateCompatibleBitmap(screen_dc, width, height);
795
796                 if(hXorBits)
797                 {
798                     if(!stretch_blt_icon(hXorBits, pDestInfo, pSrcInfo, (char*)bmi + size))
799                     {
800                         DeleteObject(hXorBits);
801                         hXorBits = 0;
802                     }
803                 }
804             }
805
806             if( hXorBits )
807             {
808                 char* xbits = (char *)bmi + size +
809                     get_dib_width_bytes( bmi->bmiHeader.biWidth,
810                                          bmi->bmiHeader.biBitCount ) * abs( bmi->bmiHeader.biHeight ) / 2;
811
812                 pSrcInfo->bmiHeader.biBitCount = 1;
813                 if (pSrcInfo->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
814                 {
815                     RGBQUAD *rgb = pSrcInfo->bmiColors;
816
817                     pSrcInfo->bmiHeader.biClrUsed = pSrcInfo->bmiHeader.biClrImportant = 2;
818                     rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
819                     rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
820                     rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
821                 }
822                 else
823                 {
824                     RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pSrcInfo) + 1);
825
826                     rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
827                     rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
828                 }
829
830                 /* Create the AND bitmap */
831                 hAndBits = CreateBitmap(width, height, 1, 1, NULL);
832
833                 if(!stretch_blt_icon(hAndBits, pDestInfo, pSrcInfo, xbits))
834                 {
835                     DeleteObject(hAndBits);
836                     hAndBits = 0;
837                 }
838
839                 if( !hAndBits )
840                 {
841                     DeleteObject( hXorBits );
842                     hXorBits = 0;
843                 }
844             }
845         }
846
847         HeapFree( GetProcessHeap(), 0, pSrcInfo );
848         HeapFree( GetProcessHeap(), 0, pDestInfo );
849     }
850
851     if( !hXorBits || !hAndBits )
852     {
853         WARN_(cursor)("\tunable to create an icon bitmap.\n");
854         return 0;
855     }
856
857     /* Now create the CURSORICONINFO structure */
858     GetObjectA( hXorBits, sizeof(bmpXor), &bmpXor );
859     GetObjectA( hAndBits, sizeof(bmpAnd), &bmpAnd );
860     sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
861     sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
862
863     hObj = GlobalAlloc16( GMEM_MOVEABLE,
864                      sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
865     if (hObj)
866     {
867         CURSORICONINFO *info;
868
869         info = GlobalLock16( hObj );
870         info->ptHotSpot.x   = hotspot.x;
871         info->ptHotSpot.y   = hotspot.y;
872         info->nWidth        = bmpXor.bmWidth;
873         info->nHeight       = bmpXor.bmHeight;
874         info->nWidthBytes   = bmpXor.bmWidthBytes;
875         info->bPlanes       = bmpXor.bmPlanes;
876         info->bBitsPerPixel = bmpXor.bmBitsPixel;
877
878         /* Transfer the bitmap bits to the CURSORICONINFO structure */
879
880         GetBitmapBits( hAndBits, sizeAnd, info + 1 );
881         GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
882         GlobalUnlock16( hObj );
883     }
884
885     DeleteObject( hAndBits );
886     DeleteObject( hXorBits );
887     return HICON_32(hObj);
888 }
889
890
891 /**********************************************************************
892  *          .ANI cursor support
893  */
894 #define RIFF_FOURCC( c0, c1, c2, c3 ) \
895         ( (DWORD)(BYTE)(c0) | ( (DWORD)(BYTE)(c1) << 8 ) | \
896         ( (DWORD)(BYTE)(c2) << 16 ) | ( (DWORD)(BYTE)(c3) << 24 ) )
897
898 #define ANI_RIFF_ID RIFF_FOURCC('R', 'I', 'F', 'F')
899 #define ANI_LIST_ID RIFF_FOURCC('L', 'I', 'S', 'T')
900 #define ANI_ACON_ID RIFF_FOURCC('A', 'C', 'O', 'N')
901 #define ANI_anih_ID RIFF_FOURCC('a', 'n', 'i', 'h')
902 #define ANI_seq__ID RIFF_FOURCC('s', 'e', 'q', ' ')
903 #define ANI_fram_ID RIFF_FOURCC('f', 'r', 'a', 'm')
904
905 #define ANI_FLAG_ICON       0x1
906 #define ANI_FLAG_SEQUENCE   0x2
907
908 typedef struct {
909     DWORD header_size;
910     DWORD num_frames;
911     DWORD num_steps;
912     DWORD width;
913     DWORD height;
914     DWORD bpp;
915     DWORD num_planes;
916     DWORD display_rate;
917     DWORD flags;
918 } ani_header;
919
920 typedef struct {
921     DWORD           data_size;
922     const unsigned char   *data;
923 } riff_chunk_t;
924
925 static void dump_ani_header( const ani_header *header )
926 {
927     TRACE("     header size: %d\n", header->header_size);
928     TRACE("          frames: %d\n", header->num_frames);
929     TRACE("           steps: %d\n", header->num_steps);
930     TRACE("           width: %d\n", header->width);
931     TRACE("          height: %d\n", header->height);
932     TRACE("             bpp: %d\n", header->bpp);
933     TRACE("          planes: %d\n", header->num_planes);
934     TRACE("    display rate: %d\n", header->display_rate);
935     TRACE("           flags: 0x%08x\n", header->flags);
936 }
937
938
939 /*
940  * RIFF:
941  * DWORD "RIFF"
942  * DWORD size
943  * DWORD riff_id
944  * BYTE[] data
945  *
946  * LIST:
947  * DWORD "LIST"
948  * DWORD size
949  * DWORD list_id
950  * BYTE[] data
951  *
952  * CHUNK:
953  * DWORD chunk_id
954  * DWORD size
955  * BYTE[] data
956  */
957 static void riff_find_chunk( DWORD chunk_id, DWORD chunk_type, const riff_chunk_t *parent_chunk, riff_chunk_t *chunk )
958 {
959     const unsigned char *ptr = parent_chunk->data;
960     const unsigned char *end = parent_chunk->data + (parent_chunk->data_size - (2 * sizeof(DWORD)));
961
962     if (chunk_type == ANI_LIST_ID || chunk_type == ANI_RIFF_ID) end -= sizeof(DWORD);
963
964     while (ptr < end)
965     {
966         if ((!chunk_type && *(DWORD *)ptr == chunk_id )
967                 || (chunk_type && *(DWORD *)ptr == chunk_type && *((DWORD *)ptr + 2) == chunk_id ))
968         {
969             ptr += sizeof(DWORD);
970             chunk->data_size = (*(DWORD *)ptr + 1) & ~1;
971             ptr += sizeof(DWORD);
972             if (chunk_type == ANI_LIST_ID || chunk_type == ANI_RIFF_ID) ptr += sizeof(DWORD);
973             chunk->data = ptr;
974
975             return;
976         }
977
978         ptr += sizeof(DWORD);
979         ptr += (*(DWORD *)ptr + 1) & ~1;
980         ptr += sizeof(DWORD);
981     }
982 }
983
984
985 /*
986  * .ANI layout:
987  *
988  * RIFF:'ACON'                  RIFF chunk
989  *     |- CHUNK:'anih'          Header
990  *     |- CHUNK:'seq '          Sequence information (optional)
991  *     \- LIST:'fram'           Frame list
992  *            |- CHUNK:icon     Cursor frames
993  *            |- CHUNK:icon
994  *            |- ...
995  *            \- CHUNK:icon
996  */
997 static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
998     INT width, INT height, INT colors )
999 {
1000     HCURSOR cursor;
1001     ani_header header = {0};
1002     LPBYTE frame_bits = 0;
1003     POINT16 hotspot;
1004     CURSORICONFILEDIRENTRY *entry;
1005
1006     riff_chunk_t root_chunk = { bits_size, bits };
1007     riff_chunk_t ACON_chunk = {0};
1008     riff_chunk_t anih_chunk = {0};
1009     riff_chunk_t fram_chunk = {0};
1010     const unsigned char *icon_data;
1011
1012     TRACE("bits %p, bits_size %d\n", bits, bits_size);
1013
1014     if (!bits) return 0;
1015
1016     riff_find_chunk( ANI_ACON_ID, ANI_RIFF_ID, &root_chunk, &ACON_chunk );
1017     if (!ACON_chunk.data)
1018     {
1019         ERR("Failed to get root chunk.\n");
1020         return 0;
1021     }
1022
1023     riff_find_chunk( ANI_anih_ID, 0, &ACON_chunk, &anih_chunk );
1024     if (!anih_chunk.data)
1025     {
1026         ERR("Failed to get 'anih' chunk.\n");
1027         return 0;
1028     }
1029     memcpy( &header, anih_chunk.data, sizeof(header) );
1030     dump_ani_header( &header );
1031
1032     riff_find_chunk( ANI_fram_ID, ANI_LIST_ID, &ACON_chunk, &fram_chunk );
1033     if (!fram_chunk.data)
1034     {
1035         ERR("Failed to get icon list.\n");
1036         return 0;
1037     }
1038
1039     /* FIXME: For now, just load the first frame.  Before we can load all the
1040      * frames, we need to write the needed code in wineserver, etc. to handle
1041      * cursors.  Once this code is written, we can extend it to support .ani
1042      * cursors and then update user32 and winex11.drv to load all frames.
1043      *
1044      * Hopefully this will at least make some games (C&C3, etc.) more playable
1045      * in the meantime.
1046      */
1047     FIXME("Loading all frames for .ani cursors not implemented.\n");
1048     icon_data = fram_chunk.data + (2 * sizeof(DWORD));
1049
1050     entry = CURSORICON_FindBestIconFile( (CURSORICONFILEDIR *) icon_data,
1051         width, height, colors );
1052
1053     frame_bits = HeapAlloc( GetProcessHeap(), 0, entry->dwDIBSize );
1054     memcpy( frame_bits, icon_data + entry->dwDIBOffset, entry->dwDIBSize );
1055
1056     if (!header.width || !header.height)
1057     {
1058         header.width = entry->bWidth;
1059         header.height = entry->bHeight;
1060     }
1061
1062     hotspot.x = entry->xHotspot;
1063     hotspot.y = entry->yHotspot;
1064
1065     cursor = CURSORICON_CreateIconFromBMI( (BITMAPINFO *) frame_bits, hotspot,
1066         FALSE, 0x00030000, header.width, header.height, 0 );
1067
1068     HeapFree( GetProcessHeap(), 0, frame_bits );
1069
1070     return cursor;
1071 }
1072
1073
1074 /**********************************************************************
1075  *              CreateIconFromResourceEx (USER32.@)
1076  *
1077  * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
1078  *        with cbSize parameter as well.
1079  */
1080 HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
1081                                        BOOL bIcon, DWORD dwVersion,
1082                                        INT width, INT height,
1083                                        UINT cFlag )
1084 {
1085     POINT16 hotspot;
1086     BITMAPINFO *bmi;
1087
1088     hotspot.x = ICON_HOTSPOT;
1089     hotspot.y = ICON_HOTSPOT;
1090
1091     TRACE_(cursor)("%p (%u bytes), ver %08x, %ix%i %s %s\n",
1092                    bits, cbSize, dwVersion, width, height,
1093                                   bIcon ? "icon" : "cursor", (cFlag & LR_MONOCHROME) ? "mono" : "" );
1094
1095     if (bIcon)
1096         bmi = (BITMAPINFO *)bits;
1097     else /* get the hotspot */
1098     {
1099         POINT16 *pt = (POINT16 *)bits;
1100         hotspot = *pt;
1101         bmi = (BITMAPINFO *)(pt + 1);
1102     }
1103
1104     return CURSORICON_CreateIconFromBMI( bmi, hotspot, bIcon, dwVersion,
1105                                          width, height, cFlag );
1106 }
1107
1108
1109 /**********************************************************************
1110  *              CreateIconFromResource (USER32.@)
1111  */
1112 HICON WINAPI CreateIconFromResource( LPBYTE bits, UINT cbSize,
1113                                            BOOL bIcon, DWORD dwVersion)
1114 {
1115     return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
1116 }
1117
1118
1119 static HICON CURSORICON_LoadFromFile( LPCWSTR filename,
1120                              INT width, INT height, INT colors,
1121                              BOOL fCursor, UINT loadflags)
1122 {
1123     CURSORICONFILEDIRENTRY *entry;
1124     CURSORICONFILEDIR *dir;
1125     DWORD filesize = 0;
1126     HICON hIcon = 0;
1127     LPBYTE bits;
1128     POINT16 hotspot;
1129
1130     TRACE("loading %s\n", debugstr_w( filename ));
1131
1132     bits = map_fileW( filename, &filesize );
1133     if (!bits)
1134         return hIcon;
1135
1136     /* Check for .ani. */
1137     if (memcmp( bits, "RIFF", 4 ) == 0)
1138     {
1139         hIcon = CURSORICON_CreateIconFromANI( bits, filesize, width, height,
1140             colors );
1141         goto end;
1142     }
1143
1144     dir = (CURSORICONFILEDIR*) bits;
1145     if ( filesize < sizeof(*dir) )
1146         goto end;
1147
1148     if ( filesize < (sizeof(*dir) + sizeof(dir->idEntries[0])*(dir->idCount-1)) )
1149         goto end;
1150
1151     if ( fCursor )
1152         entry = CURSORICON_FindBestCursorFile( dir, width, height, colors );
1153     else
1154         entry = CURSORICON_FindBestIconFile( dir, width, height, colors );
1155
1156     if ( !entry )
1157         goto end;
1158
1159     /* check that we don't run off the end of the file */
1160     if ( entry->dwDIBOffset > filesize )
1161         goto end;
1162     if ( entry->dwDIBOffset + entry->dwDIBSize > filesize )
1163         goto end;
1164
1165     /* Set the actual hotspot for cursors and ICON_HOTSPOT for icons. */
1166     if ( fCursor )
1167     {
1168         hotspot.x = entry->xHotspot;
1169         hotspot.y = entry->yHotspot;
1170     }
1171     else
1172     {
1173         hotspot.x = ICON_HOTSPOT;
1174         hotspot.y = ICON_HOTSPOT;
1175     }
1176     hIcon = CURSORICON_CreateIconFromBMI( (BITMAPINFO *)&bits[entry->dwDIBOffset],
1177                                           hotspot, !fCursor, 0x00030000,
1178                                           width, height, loadflags );
1179 end:
1180     TRACE("loaded %s -> %p\n", debugstr_w( filename ), hIcon );
1181     UnmapViewOfFile( bits );
1182     return hIcon;
1183 }
1184
1185 /**********************************************************************
1186  *          CURSORICON_Load
1187  *
1188  * Load a cursor or icon from resource or file.
1189  */
1190 static HICON CURSORICON_Load(HINSTANCE hInstance, LPCWSTR name,
1191                              INT width, INT height, INT colors,
1192                              BOOL fCursor, UINT loadflags)
1193 {
1194     HANDLE handle = 0;
1195     HICON hIcon = 0;
1196     HRSRC hRsrc, hGroupRsrc;
1197     CURSORICONDIR *dir;
1198     CURSORICONDIRENTRY *dirEntry;
1199     LPBYTE bits;
1200     WORD wResId;
1201     DWORD dwBytesInRes;
1202
1203     TRACE("%p, %s, %dx%d, colors %d, fCursor %d, flags 0x%04x\n",
1204           hInstance, debugstr_w(name), width, height, colors, fCursor, loadflags);
1205
1206     if ( loadflags & LR_LOADFROMFILE )    /* Load from file */
1207         return CURSORICON_LoadFromFile( name, width, height, colors, fCursor, loadflags );
1208
1209     if (!hInstance) hInstance = user32_module;  /* Load OEM cursor/icon */
1210
1211     /* Normalize hInstance (must be uniquely represented for icon cache) */
1212
1213     if (!HIWORD( hInstance ))
1214         hInstance = HINSTANCE_32(GetExePtr( HINSTANCE_16(hInstance) ));
1215
1216     /* Get directory resource ID */
1217
1218     if (!(hRsrc = FindResourceW( hInstance, name,
1219                                  (LPWSTR)(fCursor ? RT_GROUP_CURSOR : RT_GROUP_ICON) )))
1220         return 0;
1221     hGroupRsrc = hRsrc;
1222
1223     /* Find the best entry in the directory */
1224
1225     if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
1226     if (!(dir = LockResource( handle ))) return 0;
1227     if (fCursor)
1228         dirEntry = CURSORICON_FindBestCursorRes( dir, width, height, colors );
1229     else
1230         dirEntry = CURSORICON_FindBestIconRes( dir, width, height, colors );
1231     if (!dirEntry) return 0;
1232     wResId = dirEntry->wResId;
1233     dwBytesInRes = dirEntry->dwBytesInRes;
1234     FreeResource( handle );
1235
1236     /* Load the resource */
1237
1238     if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
1239                                 (LPWSTR)(fCursor ? RT_CURSOR : RT_ICON) ))) return 0;
1240
1241     /* If shared icon, check whether it was already loaded */
1242     if (    (loadflags & LR_SHARED)
1243          && (hIcon = CURSORICON_FindSharedIcon( hInstance, hRsrc ) ) != 0 )
1244         return hIcon;
1245
1246     if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
1247     bits = LockResource( handle );
1248     hIcon = CreateIconFromResourceEx( bits, dwBytesInRes,
1249                                       !fCursor, 0x00030000, width, height, loadflags);
1250     FreeResource( handle );
1251
1252     /* If shared icon, add to icon cache */
1253
1254     if ( hIcon && (loadflags & LR_SHARED) )
1255         CURSORICON_AddSharedIcon( hInstance, hRsrc, hGroupRsrc, hIcon );
1256
1257     return hIcon;
1258 }
1259
1260 /***********************************************************************
1261  *           CURSORICON_Copy
1262  *
1263  * Make a copy of a cursor or icon.
1264  */
1265 static HICON CURSORICON_Copy( HINSTANCE16 hInst16, HICON hIcon )
1266 {
1267     char *ptrOld, *ptrNew;
1268     int size;
1269     HICON16 hOld = HICON_16(hIcon);
1270     HICON16 hNew;
1271
1272     if (!(ptrOld = GlobalLock16( hOld ))) return 0;
1273     if (hInst16 && !(hInst16 = GetExePtr( hInst16 ))) return 0;
1274     size = GlobalSize16( hOld );
1275     hNew = GlobalAlloc16( GMEM_MOVEABLE, size );
1276     FarSetOwner16( hNew, hInst16 );
1277     ptrNew = GlobalLock16( hNew );
1278     memcpy( ptrNew, ptrOld, size );
1279     GlobalUnlock16( hOld );
1280     GlobalUnlock16( hNew );
1281     return HICON_32(hNew);
1282 }
1283
1284 /*************************************************************************
1285  * CURSORICON_ExtCopy
1286  *
1287  * Copies an Image from the Cache if LR_COPYFROMRESOURCE is specified
1288  *
1289  * PARAMS
1290  *      Handle     [I] handle to an Image
1291  *      nType      [I] Type of Handle (IMAGE_CURSOR | IMAGE_ICON)
1292  *      iDesiredCX [I] The Desired width of the Image
1293  *      iDesiredCY [I] The desired height of the Image
1294  *      nFlags     [I] The flags from CopyImage
1295  *
1296  * RETURNS
1297  *     Success: The new handle of the Image
1298  *
1299  * NOTES
1300  *     LR_COPYDELETEORG and LR_MONOCHROME are currently not implemented.
1301  *     LR_MONOCHROME should be implemented by CreateIconFromResourceEx.
1302  *     LR_COPYFROMRESOURCE will only work if the Image is in the Cache.
1303  *
1304  *
1305  */
1306
1307 static HICON CURSORICON_ExtCopy(HICON hIcon, UINT nType,
1308                                 INT iDesiredCX, INT iDesiredCY,
1309                                 UINT nFlags)
1310 {
1311     HICON hNew=0;
1312
1313     TRACE_(icon)("hIcon %p, nType %u, iDesiredCX %i, iDesiredCY %i, nFlags %u\n",
1314                  hIcon, nType, iDesiredCX, iDesiredCY, nFlags);
1315
1316     if(hIcon == 0)
1317     {
1318         return 0;
1319     }
1320
1321     /* Best Fit or Monochrome */
1322     if( (nFlags & LR_COPYFROMRESOURCE
1323         && (iDesiredCX > 0 || iDesiredCY > 0))
1324         || nFlags & LR_MONOCHROME)
1325     {
1326         ICONCACHE* pIconCache = CURSORICON_FindCache(hIcon);
1327
1328         /* Not Found in Cache, then do a straight copy
1329         */
1330         if(pIconCache == NULL)
1331         {
1332             hNew = CURSORICON_Copy(0, hIcon);
1333             if(nFlags & LR_COPYFROMRESOURCE)
1334             {
1335                 TRACE_(icon)("LR_COPYFROMRESOURCE: Failed to load from cache\n");
1336             }
1337         }
1338         else
1339         {
1340             int iTargetCY = iDesiredCY, iTargetCX = iDesiredCX;
1341             LPBYTE pBits;
1342             HANDLE hMem;
1343             HRSRC hRsrc;
1344             DWORD dwBytesInRes;
1345             WORD wResId;
1346             CURSORICONDIR *pDir;
1347             CURSORICONDIRENTRY *pDirEntry;
1348             BOOL bIsIcon = (nType == IMAGE_ICON);
1349
1350             /* Completing iDesiredCX CY for Monochrome Bitmaps if needed
1351             */
1352             if(((nFlags & LR_MONOCHROME) && !(nFlags & LR_COPYFROMRESOURCE))
1353                 || (iDesiredCX == 0 && iDesiredCY == 0))
1354             {
1355                 iDesiredCY = GetSystemMetrics(bIsIcon ?
1356                     SM_CYICON : SM_CYCURSOR);
1357                 iDesiredCX = GetSystemMetrics(bIsIcon ?
1358                     SM_CXICON : SM_CXCURSOR);
1359             }
1360
1361             /* Retrieve the CURSORICONDIRENTRY
1362             */
1363             if (!(hMem = LoadResource( pIconCache->hModule ,
1364                             pIconCache->hGroupRsrc)))
1365             {
1366                 return 0;
1367             }
1368             if (!(pDir = LockResource( hMem )))
1369             {
1370                 return 0;
1371             }
1372
1373             /* Find Best Fit
1374             */
1375             if(bIsIcon)
1376             {
1377                 pDirEntry = CURSORICON_FindBestIconRes(
1378                                 pDir, iDesiredCX, iDesiredCY, 256 );
1379             }
1380             else
1381             {
1382                 pDirEntry = CURSORICON_FindBestCursorRes(
1383                                 pDir, iDesiredCX, iDesiredCY, 1);
1384             }
1385
1386             wResId = pDirEntry->wResId;
1387             dwBytesInRes = pDirEntry->dwBytesInRes;
1388             FreeResource(hMem);
1389
1390             TRACE_(icon)("ResID %u, BytesInRes %u, Width %d, Height %d DX %d, DY %d\n",
1391                 wResId, dwBytesInRes,  pDirEntry->ResInfo.icon.bWidth,
1392                 pDirEntry->ResInfo.icon.bHeight, iDesiredCX, iDesiredCY);
1393
1394             /* Get the Best Fit
1395             */
1396             if (!(hRsrc = FindResourceW(pIconCache->hModule ,
1397                 MAKEINTRESOURCEW(wResId), (LPWSTR)(bIsIcon ? RT_ICON : RT_CURSOR))))
1398             {
1399                 return 0;
1400             }
1401             if (!(hMem = LoadResource( pIconCache->hModule , hRsrc )))
1402             {
1403                 return 0;
1404             }
1405
1406             pBits = LockResource( hMem );
1407
1408             if(nFlags & LR_DEFAULTSIZE)
1409             {
1410                 iTargetCY = GetSystemMetrics(SM_CYICON);
1411                 iTargetCX = GetSystemMetrics(SM_CXICON);
1412             }
1413
1414             /* Create a New Icon with the proper dimension
1415             */
1416             hNew = CreateIconFromResourceEx( pBits, dwBytesInRes,
1417                        bIsIcon, 0x00030000, iTargetCX, iTargetCY, nFlags);
1418             FreeResource(hMem);
1419         }
1420     }
1421     else hNew = CURSORICON_Copy(0, hIcon);
1422     return hNew;
1423 }
1424
1425
1426 /***********************************************************************
1427  *              CreateCursor (USER32.@)
1428  */
1429 HCURSOR WINAPI CreateCursor( HINSTANCE hInstance,
1430                                  INT xHotSpot, INT yHotSpot,
1431                                  INT nWidth, INT nHeight,
1432                                  LPCVOID lpANDbits, LPCVOID lpXORbits )
1433 {
1434     ICONINFO info;
1435     HCURSOR hCursor;
1436
1437     TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1438                     nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1439
1440     info.fIcon = FALSE;
1441     info.xHotspot = xHotSpot;
1442     info.yHotspot = yHotSpot;
1443     info.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpANDbits );
1444     info.hbmColor = CreateBitmap( nWidth, nHeight, 1, 1, lpXORbits );
1445     hCursor = CreateIconIndirect( &info );
1446     DeleteObject( info.hbmMask );
1447     DeleteObject( info.hbmColor );
1448     return hCursor;
1449 }
1450
1451
1452 /***********************************************************************
1453  *              CreateIcon (USER.407)
1454  */
1455 HICON16 WINAPI CreateIcon16( HINSTANCE16 hInstance, INT16 nWidth,
1456                              INT16 nHeight, BYTE bPlanes, BYTE bBitsPixel,
1457                              LPCVOID lpANDbits, LPCVOID lpXORbits )
1458 {
1459     CURSORICONINFO info;
1460
1461     TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1462                   nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1463
1464     info.ptHotSpot.x = ICON_HOTSPOT;
1465     info.ptHotSpot.y = ICON_HOTSPOT;
1466     info.nWidth = nWidth;
1467     info.nHeight = nHeight;
1468     info.nWidthBytes = 0;
1469     info.bPlanes = bPlanes;
1470     info.bBitsPerPixel = bBitsPixel;
1471
1472     return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1473 }
1474
1475
1476 /***********************************************************************
1477  *              CreateIcon (USER32.@)
1478  *
1479  *  Creates an icon based on the specified bitmaps. The bitmaps must be
1480  *  provided in a device dependent format and will be resized to
1481  *  (SM_CXICON,SM_CYICON) and depth converted to match the screen's color
1482  *  depth. The provided bitmaps must be top-down bitmaps.
1483  *  Although Windows does not support 15bpp(*) this API must support it
1484  *  for Winelib applications.
1485  *
1486  *  (*) Windows does not support 15bpp but it supports the 555 RGB 16bpp
1487  *      format!
1488  *
1489  * RETURNS
1490  *  Success: handle to an icon
1491  *  Failure: NULL
1492  *
1493  * FIXME: Do we need to resize the bitmaps?
1494  */
1495 HICON WINAPI CreateIcon(
1496     HINSTANCE hInstance,  /* [in] the application's hInstance */
1497     INT       nWidth,     /* [in] the width of the provided bitmaps */
1498     INT       nHeight,    /* [in] the height of the provided bitmaps */
1499     BYTE      bPlanes,    /* [in] the number of planes in the provided bitmaps */
1500     BYTE      bBitsPixel, /* [in] the number of bits per pixel of the lpXORbits bitmap */
1501     LPCVOID   lpANDbits,  /* [in] a monochrome bitmap representing the icon's mask */
1502     LPCVOID   lpXORbits)  /* [in] the icon's 'color' bitmap */
1503 {
1504     ICONINFO iinfo;
1505     HICON hIcon;
1506
1507     TRACE_(icon)("%dx%d, planes %d, bpp %d, xor %p, and %p\n",
1508                  nWidth, nHeight, bPlanes, bBitsPixel, lpXORbits, lpANDbits);
1509
1510     iinfo.fIcon = TRUE;
1511     iinfo.xHotspot = ICON_HOTSPOT;
1512     iinfo.yHotspot = ICON_HOTSPOT;
1513     iinfo.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpANDbits );
1514     iinfo.hbmColor = CreateBitmap( nWidth, nHeight, bPlanes, bBitsPixel, lpXORbits );
1515
1516     hIcon = CreateIconIndirect( &iinfo );
1517
1518     DeleteObject( iinfo.hbmMask );
1519     DeleteObject( iinfo.hbmColor );
1520
1521     return hIcon;
1522 }
1523
1524
1525 /***********************************************************************
1526  *              CreateCursorIconIndirect (USER.408)
1527  */
1528 HGLOBAL16 WINAPI CreateCursorIconIndirect16( HINSTANCE16 hInstance,
1529                                            CURSORICONINFO *info,
1530                                            LPCVOID lpANDbits,
1531                                            LPCVOID lpXORbits )
1532 {
1533     HGLOBAL16 handle;
1534     char *ptr;
1535     int sizeAnd, sizeXor;
1536
1537     hInstance = GetExePtr( hInstance );  /* Make it a module handle */
1538     if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
1539     info->nWidthBytes = get_bitmap_width_bytes(info->nWidth,info->bBitsPerPixel);
1540     sizeXor = info->nHeight * info->nWidthBytes;
1541     sizeAnd = info->nHeight * get_bitmap_width_bytes( info->nWidth, 1 );
1542     if (!(handle = GlobalAlloc16( GMEM_MOVEABLE,
1543                                   sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
1544         return 0;
1545     FarSetOwner16( handle, hInstance );
1546     ptr = GlobalLock16( handle );
1547     memcpy( ptr, info, sizeof(*info) );
1548     memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
1549     memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
1550     GlobalUnlock16( handle );
1551     return handle;
1552 }
1553
1554
1555 /***********************************************************************
1556  *              CopyIcon (USER.368)
1557  */
1558 HICON16 WINAPI CopyIcon16( HINSTANCE16 hInstance, HICON16 hIcon )
1559 {
1560     CURSORICONINFO *info = GlobalLock16( hIcon );
1561     void *and_bits = info + 1;
1562     void *xor_bits = (BYTE *)and_bits + info->nHeight * get_bitmap_width_bytes( info->nWidth, 1 );
1563     HGLOBAL16 ret = CreateCursorIconIndirect16( hInstance, info, and_bits, xor_bits );
1564     GlobalUnlock16( hIcon );
1565     return ret;
1566 }
1567
1568
1569 /***********************************************************************
1570  *              CopyIcon (USER32.@)
1571  */
1572 HICON WINAPI CopyIcon( HICON hIcon )
1573 {
1574     TRACE_(icon)("%p\n", hIcon );
1575     return CURSORICON_Copy( 0, hIcon );
1576 }
1577
1578
1579 /***********************************************************************
1580  *              CopyCursor (USER.369)
1581  */
1582 HCURSOR16 WINAPI CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
1583 {
1584     CURSORICONINFO *info = GlobalLock16( hCursor );
1585     void *and_bits = info + 1;
1586     void *xor_bits = (BYTE *)and_bits + info->nHeight * get_bitmap_width_bytes( info->nWidth, 1 );
1587     HGLOBAL16 ret = CreateCursorIconIndirect16( hInstance, info, and_bits, xor_bits );
1588     GlobalUnlock16( hCursor );
1589     return ret;
1590 }
1591
1592
1593 /**********************************************************************
1594  *              DestroyIcon32 (USER.610)
1595  *
1596  * This routine is actually exported from Win95 USER under the name
1597  * DestroyIcon32 ...  The behaviour implemented here should mimic
1598  * the Win95 one exactly, especially the return values, which
1599  * depend on the setting of various flags.
1600  */
1601 WORD WINAPI DestroyIcon32( HGLOBAL16 handle, UINT16 flags )
1602 {
1603     WORD retv;
1604
1605     TRACE_(icon)("(%04x, %04x)\n", handle, flags );
1606
1607     /* Check whether destroying active cursor */
1608
1609     if ( get_user_thread_info()->cursor == HICON_32(handle) )
1610     {
1611         WARN_(cursor)("Destroying active cursor!\n" );
1612         return FALSE;
1613     }
1614
1615     /* Try shared cursor/icon first */
1616
1617     if ( !(flags & CID_NONSHARED) )
1618     {
1619         INT count = CURSORICON_DelSharedIcon(HICON_32(handle));
1620
1621         if ( count != -1 )
1622             return (flags & CID_WIN32)? TRUE : (count == 0);
1623
1624         /* FIXME: OEM cursors/icons should be recognized */
1625     }
1626
1627     /* Now assume non-shared cursor/icon */
1628
1629     retv = GlobalFree16( handle );
1630     return (flags & CID_RESOURCE)? retv : TRUE;
1631 }
1632
1633 /***********************************************************************
1634  *              DestroyIcon (USER32.@)
1635  */
1636 BOOL WINAPI DestroyIcon( HICON hIcon )
1637 {
1638     return DestroyIcon32(HICON_16(hIcon), CID_WIN32);
1639 }
1640
1641
1642 /***********************************************************************
1643  *              DestroyCursor (USER32.@)
1644  */
1645 BOOL WINAPI DestroyCursor( HCURSOR hCursor )
1646 {
1647     return DestroyIcon32(HCURSOR_16(hCursor), CID_WIN32);
1648 }
1649
1650 /***********************************************************************
1651  *      bitmap_has_alpha_channel
1652  *
1653  * Analyses bits bitmap to determine if alpha data is present.
1654  *
1655  * PARAMS
1656  *      bpp          [I] The bits-per-pixel of the bitmap
1657  *      bitmapBits   [I] A pointer to the bitmap data
1658  *      bitmapLength [I] The length of the bitmap in bytes
1659  *
1660  * RETURNS
1661  *      TRUE if an alpha channel is discovered, FALSE
1662  *
1663  * NOTE
1664  *      Windows' behaviour is that if the icon bitmap is 32-bit and at
1665  *      least one pixel has a non-zero alpha, then the bitmap is a
1666  *      treated as having an alpha channel transparentcy. Otherwise,
1667  *      it's treated as being completely opaque.
1668  *
1669  */
1670 static BOOL bitmap_has_alpha_channel( int bpp, unsigned char *bitmapBits,
1671                                       unsigned int bitmapLength )
1672 {
1673     /* Detect an alpha channel by looking for non-zero alpha pixels */
1674     if(bpp == 32)
1675     {
1676         unsigned int offset;
1677         for(offset = 3; offset < bitmapLength; offset += 4)
1678         {
1679             if(bitmapBits[offset] != 0)
1680             {
1681                 return TRUE;
1682             }
1683         }
1684     }
1685     return FALSE;
1686 }
1687
1688 /***********************************************************************
1689  *          premultiply_alpha_channel
1690  *
1691  * Premultiplies the color channels of a 32-bit bitmap by the alpha
1692  * channel. This is a necessary step that must be carried out on
1693  * the image before it is passed to GdiAlphaBlend
1694  *
1695  * PARAMS
1696  *      destBitmap   [I] The destination bitmap buffer
1697  *      srcBitmap    [I] The source bitmap buffer
1698  *      bitmapLength [I] The length of the bitmap in bytes
1699  *
1700  */
1701 static void premultiply_alpha_channel( unsigned char *destBitmap,
1702                                        unsigned char *srcBitmap,
1703                                        unsigned int bitmapLength )
1704 {
1705     unsigned char *destPixel = destBitmap;
1706     unsigned char *srcPixel = srcBitmap;
1707
1708     while(destPixel < destBitmap + bitmapLength)
1709     {
1710         unsigned char alpha = srcPixel[3];
1711         *(destPixel++) = *(srcPixel++) * alpha / 255;
1712         *(destPixel++) = *(srcPixel++) * alpha / 255;
1713         *(destPixel++) = *(srcPixel++) * alpha / 255;
1714         *(destPixel++) = *(srcPixel++);
1715     }
1716 }
1717
1718 /***********************************************************************
1719  *              DrawIcon (USER32.@)
1720  */
1721 BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
1722 {
1723     CURSORICONINFO *ptr;
1724     HDC hMemDC;
1725     HBITMAP hXorBits = NULL, hAndBits = NULL, hBitTemp = NULL;
1726     COLORREF oldFg, oldBg;
1727     unsigned char *xorBitmapBits;
1728     unsigned int dibLength;
1729
1730     TRACE("%p, (%d,%d), %p\n", hdc, x, y, hIcon);
1731
1732     if (!(ptr = GlobalLock16(HICON_16(hIcon)))) return FALSE;
1733     if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
1734
1735     dibLength = ptr->nHeight * get_bitmap_width_bytes(
1736         ptr->nWidth, ptr->bBitsPerPixel);
1737
1738     xorBitmapBits = (unsigned char *)(ptr + 1) + ptr->nHeight *
1739                     get_bitmap_width_bytes(ptr->nWidth, 1);
1740
1741     oldFg = SetTextColor( hdc, RGB(0,0,0) );
1742     oldBg = SetBkColor( hdc, RGB(255,255,255) );
1743
1744     if(bitmap_has_alpha_channel(ptr->bBitsPerPixel, xorBitmapBits, dibLength))
1745     {
1746         BITMAPINFOHEADER bmih;
1747         unsigned char *dibBits;
1748
1749         memset(&bmih, 0, sizeof(BITMAPINFOHEADER));
1750         bmih.biSize = sizeof(BITMAPINFOHEADER);
1751         bmih.biWidth = ptr->nWidth;
1752         bmih.biHeight = -ptr->nHeight;
1753         bmih.biPlanes = ptr->bPlanes;
1754         bmih.biBitCount = 32;
1755         bmih.biCompression = BI_RGB;
1756
1757         hXorBits = CreateDIBSection(hdc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS,
1758                                     (void*)&dibBits, NULL, 0);
1759
1760         if (hXorBits && dibBits)
1761         {
1762             BLENDFUNCTION pixelblend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
1763
1764             /* Do the alpha blending render */
1765             premultiply_alpha_channel(dibBits, xorBitmapBits, dibLength);
1766             hBitTemp = SelectObject( hMemDC, hXorBits );
1767             /* Destination width/height has to be "System Large" size */
1768             GdiAlphaBlend(hdc, x, y, GetSystemMetrics(SM_CXICON),
1769                             GetSystemMetrics(SM_CYICON), hMemDC,
1770                             0, 0, ptr->nWidth, ptr->nHeight, pixelblend);
1771             SelectObject( hMemDC, hBitTemp );
1772         }
1773     }
1774     else
1775     {
1776         hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1, ptr + 1 );
1777         hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
1778                                ptr->bBitsPerPixel, xorBitmapBits);
1779
1780         if (hXorBits && hAndBits)
1781         {
1782             hBitTemp = SelectObject( hMemDC, hAndBits );
1783             StretchBlt( hdc, x, y, GetSystemMetrics(SM_CXICON),
1784                             GetSystemMetrics(SM_CYICON), hMemDC, 0, 0,
1785                             ptr->nWidth, ptr->nHeight, SRCAND );
1786             SelectObject( hMemDC, hXorBits );
1787             StretchBlt( hdc, x, y, GetSystemMetrics(SM_CXICON),
1788                             GetSystemMetrics(SM_CYICON), hMemDC, 0, 0,
1789                             ptr->nWidth, ptr->nHeight, SRCINVERT );
1790             SelectObject( hMemDC, hBitTemp );
1791         }
1792     }
1793
1794     DeleteDC( hMemDC );
1795     if (hXorBits) DeleteObject( hXorBits );
1796     if (hAndBits) DeleteObject( hAndBits );
1797     GlobalUnlock16(HICON_16(hIcon));
1798     SetTextColor( hdc, oldFg );
1799     SetBkColor( hdc, oldBg );
1800     return TRUE;
1801 }
1802
1803 /***********************************************************************
1804  *              DumpIcon (USER.459)
1805  */
1806 DWORD WINAPI DumpIcon16( SEGPTR pInfo, WORD *lpLen,
1807                        SEGPTR *lpXorBits, SEGPTR *lpAndBits )
1808 {
1809     CURSORICONINFO *info = MapSL( pInfo );
1810     int sizeAnd, sizeXor;
1811
1812     if (!info) return 0;
1813     sizeXor = info->nHeight * info->nWidthBytes;
1814     sizeAnd = info->nHeight * get_bitmap_width_bytes( info->nWidth, 1 );
1815     if (lpAndBits) *lpAndBits = pInfo + sizeof(CURSORICONINFO);
1816     if (lpXorBits) *lpXorBits = pInfo + sizeof(CURSORICONINFO) + sizeAnd;
1817     if (lpLen) *lpLen = sizeof(CURSORICONINFO) + sizeAnd + sizeXor;
1818     return MAKELONG( sizeXor, sizeXor );
1819 }
1820
1821
1822 /***********************************************************************
1823  *              SetCursor (USER32.@)
1824  *
1825  * Set the cursor shape.
1826  *
1827  * RETURNS
1828  *      A handle to the previous cursor shape.
1829  */
1830 HCURSOR WINAPI DECLSPEC_HOTPATCH SetCursor( HCURSOR hCursor /* [in] Handle of cursor to show */ )
1831 {
1832     struct user_thread_info *thread_info = get_user_thread_info();
1833     HCURSOR hOldCursor;
1834
1835     if (hCursor == thread_info->cursor) return hCursor;  /* No change */
1836     TRACE("%p\n", hCursor);
1837     hOldCursor = thread_info->cursor;
1838     thread_info->cursor = hCursor;
1839     /* Change the cursor shape only if it is visible */
1840     if (thread_info->cursor_count >= 0)
1841     {
1842         USER_Driver->pSetCursor(GlobalLock16(HCURSOR_16(hCursor)));
1843         GlobalUnlock16(HCURSOR_16(hCursor));
1844     }
1845     return hOldCursor;
1846 }
1847
1848 /***********************************************************************
1849  *              ShowCursor (USER32.@)
1850  */
1851 INT WINAPI DECLSPEC_HOTPATCH ShowCursor( BOOL bShow )
1852 {
1853     struct user_thread_info *thread_info = get_user_thread_info();
1854
1855     TRACE("%d, count=%d\n", bShow, thread_info->cursor_count );
1856
1857     if (bShow)
1858     {
1859         if (++thread_info->cursor_count == 0) /* Show it */
1860         {
1861             USER_Driver->pSetCursor(GlobalLock16(HCURSOR_16(thread_info->cursor)));
1862             GlobalUnlock16(HCURSOR_16(thread_info->cursor));
1863         }
1864     }
1865     else
1866     {
1867         if (--thread_info->cursor_count == -1) /* Hide it */
1868             USER_Driver->pSetCursor( NULL );
1869     }
1870     return thread_info->cursor_count;
1871 }
1872
1873 /***********************************************************************
1874  *              GetCursor (USER32.@)
1875  */
1876 HCURSOR WINAPI GetCursor(void)
1877 {
1878     return get_user_thread_info()->cursor;
1879 }
1880
1881
1882 /***********************************************************************
1883  *              ClipCursor (USER32.@)
1884  */
1885 BOOL WINAPI DECLSPEC_HOTPATCH ClipCursor( const RECT *rect )
1886 {
1887     RECT virt;
1888
1889     SetRect( &virt, 0, 0, GetSystemMetrics( SM_CXVIRTUALSCREEN ),
1890                           GetSystemMetrics( SM_CYVIRTUALSCREEN ) );
1891     OffsetRect( &virt, GetSystemMetrics( SM_XVIRTUALSCREEN ),
1892                        GetSystemMetrics( SM_YVIRTUALSCREEN ) );
1893
1894     TRACE( "Clipping to: %s was: %s screen: %s\n", wine_dbgstr_rect(rect),
1895            wine_dbgstr_rect(&CURSOR_ClipRect), wine_dbgstr_rect(&virt) );
1896
1897     if (!IntersectRect( &CURSOR_ClipRect, &virt, rect ))
1898         CURSOR_ClipRect = virt;
1899
1900     USER_Driver->pClipCursor( rect );
1901     return TRUE;
1902 }
1903
1904
1905 /***********************************************************************
1906  *              GetClipCursor (USER32.@)
1907  */
1908 BOOL WINAPI DECLSPEC_HOTPATCH GetClipCursor( RECT *rect )
1909 {
1910     /* If this is first time - initialize the rect */
1911     if (IsRectEmpty( &CURSOR_ClipRect )) ClipCursor( NULL );
1912
1913     return CopyRect( rect, &CURSOR_ClipRect );
1914 }
1915
1916
1917 /***********************************************************************
1918  *              SetSystemCursor (USER32.@)
1919  */
1920 BOOL WINAPI SetSystemCursor(HCURSOR hcur, DWORD id)
1921 {
1922     FIXME("(%p,%08x),stub!\n",  hcur, id);
1923     return TRUE;
1924 }
1925
1926
1927 /**********************************************************************
1928  *              LookupIconIdFromDirectoryEx (USER.364)
1929  *
1930  * FIXME: exact parameter sizes
1931  */
1932 INT16 WINAPI LookupIconIdFromDirectoryEx16( LPBYTE dir, BOOL16 bIcon,
1933                                             INT16 width, INT16 height, UINT16 cFlag )
1934 {
1935     return LookupIconIdFromDirectoryEx( dir, bIcon, width, height, cFlag );
1936 }
1937
1938 /**********************************************************************
1939  *              LookupIconIdFromDirectoryEx (USER32.@)
1940  */
1941 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE xdir, BOOL bIcon,
1942              INT width, INT height, UINT cFlag )
1943 {
1944     CURSORICONDIR       *dir = (CURSORICONDIR*)xdir;
1945     UINT retVal = 0;
1946     if( dir && !dir->idReserved && (dir->idType & 3) )
1947     {
1948         CURSORICONDIRENTRY* entry;
1949         HDC hdc;
1950         UINT palEnts;
1951         int colors;
1952         hdc = GetDC(0);
1953         palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
1954         if (palEnts == 0)
1955             palEnts = 256;
1956         colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
1957
1958         ReleaseDC(0, hdc);
1959
1960         if( bIcon )
1961             entry = CURSORICON_FindBestIconRes( dir, width, height, colors );
1962         else
1963             entry = CURSORICON_FindBestCursorRes( dir, width, height, colors );
1964
1965         if( entry ) retVal = entry->wResId;
1966     }
1967     else WARN_(cursor)("invalid resource directory\n");
1968     return retVal;
1969 }
1970
1971 /**********************************************************************
1972  *              LookupIconIdFromDirectory (USER32.@)
1973  */
1974 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1975 {
1976     return LookupIconIdFromDirectoryEx( dir, bIcon,
1977            bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1978            bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1979 }
1980
1981 /**********************************************************************
1982  *              GetIconID (USER.455)
1983  */
1984 WORD WINAPI GetIconID16( HGLOBAL16 hResource, DWORD resType )
1985 {
1986     LPBYTE lpDir = GlobalLock16(hResource);
1987
1988     TRACE_(cursor)("hRes=%04x, entries=%i\n",
1989                     hResource, lpDir ? ((CURSORICONDIR*)lpDir)->idCount : 0);
1990
1991     switch(resType)
1992     {
1993         case RT_CURSOR:
1994              return (WORD)LookupIconIdFromDirectoryEx16( lpDir, FALSE,
1995                           GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1996         case RT_ICON:
1997              return (WORD)LookupIconIdFromDirectoryEx16( lpDir, TRUE,
1998                           GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0 );
1999         default:
2000              WARN_(cursor)("invalid res type %d\n", resType );
2001     }
2002     return 0;
2003 }
2004
2005 /**********************************************************************
2006  *              LoadCursorIconHandler (USER.336)
2007  *
2008  * Supposed to load resources of Windows 2.x applications.
2009  */
2010 HGLOBAL16 WINAPI LoadCursorIconHandler16( HGLOBAL16 hResource, HMODULE16 hModule, HRSRC16 hRsrc )
2011 {
2012     FIXME_(cursor)("(%04x,%04x,%04x): old 2.x resources are not supported!\n",
2013           hResource, hModule, hRsrc);
2014     return 0;
2015 }
2016
2017 /**********************************************************************
2018  *              LoadIconHandler (USER.456)
2019  */
2020 HICON16 WINAPI LoadIconHandler16( HGLOBAL16 hResource, BOOL16 bNew )
2021 {
2022     LPBYTE bits = LockResource16( hResource );
2023
2024     TRACE_(cursor)("hRes=%04x\n",hResource);
2025
2026     return HICON_16(CreateIconFromResourceEx( bits, 0, TRUE,
2027                       bNew ? 0x00030000 : 0x00020000, 0, 0, LR_DEFAULTCOLOR));
2028 }
2029
2030 /***********************************************************************
2031  *              LoadCursorW (USER32.@)
2032  */
2033 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
2034 {
2035     TRACE("%p, %s\n", hInstance, debugstr_w(name));
2036
2037     return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0,
2038                        LR_SHARED | LR_DEFAULTSIZE );
2039 }
2040
2041 /***********************************************************************
2042  *              LoadCursorA (USER32.@)
2043  */
2044 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
2045 {
2046     TRACE("%p, %s\n", hInstance, debugstr_a(name));
2047
2048     return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0,
2049                        LR_SHARED | LR_DEFAULTSIZE );
2050 }
2051
2052 /***********************************************************************
2053  *              LoadCursorFromFileW (USER32.@)
2054  */
2055 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
2056 {
2057     TRACE("%s\n", debugstr_w(name));
2058
2059     return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0,
2060                        LR_LOADFROMFILE | LR_DEFAULTSIZE );
2061 }
2062
2063 /***********************************************************************
2064  *              LoadCursorFromFileA (USER32.@)
2065  */
2066 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
2067 {
2068     TRACE("%s\n", debugstr_a(name));
2069
2070     return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0,
2071                        LR_LOADFROMFILE | LR_DEFAULTSIZE );
2072 }
2073
2074 /***********************************************************************
2075  *              LoadIconW (USER32.@)
2076  */
2077 HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
2078 {
2079     TRACE("%p, %s\n", hInstance, debugstr_w(name));
2080
2081     return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0,
2082                        LR_SHARED | LR_DEFAULTSIZE );
2083 }
2084
2085 /***********************************************************************
2086  *              LoadIconA (USER32.@)
2087  */
2088 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
2089 {
2090     TRACE("%p, %s\n", hInstance, debugstr_a(name));
2091
2092     return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0,
2093                        LR_SHARED | LR_DEFAULTSIZE );
2094 }
2095
2096 /**********************************************************************
2097  *              GetIconInfo (USER32.@)
2098  */
2099 BOOL WINAPI GetIconInfo(HICON hIcon, PICONINFO iconinfo)
2100 {
2101     CURSORICONINFO *ciconinfo;
2102     INT height;
2103
2104     ciconinfo = GlobalLock16(HICON_16(hIcon));
2105     if (!ciconinfo)
2106         return FALSE;
2107
2108     TRACE("%p => %dx%d, %d bpp\n", hIcon,
2109           ciconinfo->nWidth, ciconinfo->nHeight, ciconinfo->bBitsPerPixel);
2110
2111     if ( (ciconinfo->ptHotSpot.x == ICON_HOTSPOT) &&
2112          (ciconinfo->ptHotSpot.y == ICON_HOTSPOT) )
2113     {
2114       iconinfo->fIcon    = TRUE;
2115       iconinfo->xHotspot = ciconinfo->nWidth / 2;
2116       iconinfo->yHotspot = ciconinfo->nHeight / 2;
2117     }
2118     else
2119     {
2120       iconinfo->fIcon    = FALSE;
2121       iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
2122       iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
2123     }
2124
2125     height = ciconinfo->nHeight;
2126
2127     if (ciconinfo->bBitsPerPixel > 1)
2128     {
2129         iconinfo->hbmColor = CreateBitmap( ciconinfo->nWidth, ciconinfo->nHeight,
2130                                 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
2131                                 (char *)(ciconinfo + 1)
2132                                 + ciconinfo->nHeight *
2133                                 get_bitmap_width_bytes (ciconinfo->nWidth,1) );
2134     }
2135     else
2136     {
2137         iconinfo->hbmColor = 0;
2138         height *= 2;
2139     }
2140
2141     iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, height,
2142                                 1, 1, ciconinfo + 1);
2143
2144     GlobalUnlock16(HICON_16(hIcon));
2145
2146     return TRUE;
2147 }
2148
2149 /**********************************************************************
2150  *              CreateIconIndirect (USER32.@)
2151  */
2152 HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
2153 {
2154     DIBSECTION bmpXor;
2155     BITMAP bmpAnd;
2156     HICON16 hObj;
2157     int xor_objsize = 0, sizeXor = 0, sizeAnd, planes, bpp;
2158
2159     TRACE("color %p, mask %p, hotspot %ux%u, fIcon %d\n",
2160            iconinfo->hbmColor, iconinfo->hbmMask,
2161            iconinfo->xHotspot, iconinfo->yHotspot, iconinfo->fIcon);
2162
2163     if (!iconinfo->hbmMask) return 0;
2164
2165     planes = GetDeviceCaps( screen_dc, PLANES );
2166     bpp = GetDeviceCaps( screen_dc, BITSPIXEL );
2167
2168     if (iconinfo->hbmColor)
2169     {
2170         xor_objsize = GetObjectW( iconinfo->hbmColor, sizeof(bmpXor), &bmpXor );
2171         TRACE("color: width %d, height %d, width bytes %d, planes %u, bpp %u\n",
2172                bmpXor.dsBm.bmWidth, bmpXor.dsBm.bmHeight, bmpXor.dsBm.bmWidthBytes,
2173                bmpXor.dsBm.bmPlanes, bmpXor.dsBm.bmBitsPixel);
2174         /* we can use either depth 1 or screen depth for xor bitmap */
2175         if (bmpXor.dsBm.bmPlanes == 1 && bmpXor.dsBm.bmBitsPixel == 1) planes = bpp = 1;
2176         sizeXor = bmpXor.dsBm.bmHeight * planes * get_bitmap_width_bytes( bmpXor.dsBm.bmWidth, bpp );
2177     }
2178     GetObjectW( iconinfo->hbmMask, sizeof(bmpAnd), &bmpAnd );
2179     TRACE("mask: width %d, height %d, width bytes %d, planes %u, bpp %u\n",
2180            bmpAnd.bmWidth, bmpAnd.bmHeight, bmpAnd.bmWidthBytes,
2181            bmpAnd.bmPlanes, bmpAnd.bmBitsPixel);
2182
2183     sizeAnd = bmpAnd.bmHeight * get_bitmap_width_bytes(bmpAnd.bmWidth, 1);
2184
2185     hObj = GlobalAlloc16( GMEM_MOVEABLE,
2186                           sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
2187     if (hObj)
2188     {
2189         CURSORICONINFO *info;
2190
2191         info = GlobalLock16( hObj );
2192
2193         /* If we are creating an icon, the hotspot is unused */
2194         if (iconinfo->fIcon)
2195         {
2196             info->ptHotSpot.x   = ICON_HOTSPOT;
2197             info->ptHotSpot.y   = ICON_HOTSPOT;
2198         }
2199         else
2200         {
2201             info->ptHotSpot.x   = iconinfo->xHotspot;
2202             info->ptHotSpot.y   = iconinfo->yHotspot;
2203         }
2204
2205         if (iconinfo->hbmColor)
2206         {
2207             info->nWidth        = bmpXor.dsBm.bmWidth;
2208             info->nHeight       = bmpXor.dsBm.bmHeight;
2209             info->nWidthBytes   = bmpXor.dsBm.bmWidthBytes;
2210             info->bPlanes       = planes;
2211             info->bBitsPerPixel = bpp;
2212         }
2213         else
2214         {
2215             info->nWidth        = bmpAnd.bmWidth;
2216             info->nHeight       = bmpAnd.bmHeight / 2;
2217             info->nWidthBytes   = get_bitmap_width_bytes(bmpAnd.bmWidth, 1);
2218             info->bPlanes       = 1;
2219             info->bBitsPerPixel = 1;
2220         }
2221
2222         /* Transfer the bitmap bits to the CURSORICONINFO structure */
2223
2224         /* Some apps pass a color bitmap as a mask, convert it to b/w */
2225         if (bmpAnd.bmBitsPixel == 1)
2226         {
2227             GetBitmapBits( iconinfo->hbmMask, sizeAnd, info + 1 );
2228         }
2229         else
2230         {
2231             HDC hdc_mem, hdc_mem2;
2232             HBITMAP hbmp_mem_old, hbmp_mem2_old, hbmp_mono;
2233
2234             hdc_mem = CreateCompatibleDC( 0 );
2235             hdc_mem2 = CreateCompatibleDC( 0 );
2236
2237             hbmp_mono = CreateBitmap( bmpAnd.bmWidth, bmpAnd.bmHeight, 1, 1, NULL );
2238
2239             hbmp_mem_old = SelectObject( hdc_mem, iconinfo->hbmMask );
2240             hbmp_mem2_old = SelectObject( hdc_mem2, hbmp_mono );
2241
2242             BitBlt( hdc_mem2, 0, 0, bmpAnd.bmWidth, bmpAnd.bmHeight, hdc_mem, 0, 0, SRCCOPY );
2243
2244             SelectObject( hdc_mem, hbmp_mem_old );
2245             SelectObject( hdc_mem2, hbmp_mem2_old );
2246
2247             DeleteDC( hdc_mem );
2248             DeleteDC( hdc_mem2 );
2249
2250             GetBitmapBits( hbmp_mono, sizeAnd, info + 1 );
2251             DeleteObject( hbmp_mono );
2252         }
2253
2254         if (iconinfo->hbmColor)
2255         {
2256             char *dst_bits = (char*)(info + 1) + sizeAnd;
2257
2258             if (bmpXor.dsBm.bmPlanes == planes && bmpXor.dsBm.bmBitsPixel == bpp)
2259                 GetBitmapBits( iconinfo->hbmColor, sizeXor, dst_bits );
2260             else
2261             {
2262                 BITMAPINFO bminfo;
2263                 int dib_width = get_dib_width_bytes( info->nWidth, info->bBitsPerPixel );
2264                 int bitmap_width = get_bitmap_width_bytes( info->nWidth, info->bBitsPerPixel );
2265
2266                 bminfo.bmiHeader.biSize = sizeof(bminfo);
2267                 bminfo.bmiHeader.biWidth = info->nWidth;
2268                 bminfo.bmiHeader.biHeight = info->nHeight;
2269                 bminfo.bmiHeader.biPlanes = info->bPlanes;
2270                 bminfo.bmiHeader.biBitCount = info->bBitsPerPixel;
2271                 bminfo.bmiHeader.biCompression = BI_RGB;
2272                 bminfo.bmiHeader.biSizeImage = info->nHeight * dib_width;
2273                 bminfo.bmiHeader.biXPelsPerMeter = 0;
2274                 bminfo.bmiHeader.biYPelsPerMeter = 0;
2275                 bminfo.bmiHeader.biClrUsed = 0;
2276                 bminfo.bmiHeader.biClrImportant = 0;
2277
2278                 /* swap lines for dib sections */
2279                 if (xor_objsize == sizeof(DIBSECTION))
2280                     bminfo.bmiHeader.biHeight = -bminfo.bmiHeader.biHeight;
2281
2282                 if (dib_width != bitmap_width)  /* need to fixup alignment */
2283                 {
2284                     char *src_bits = HeapAlloc( GetProcessHeap(), 0, bminfo.bmiHeader.biSizeImage );
2285
2286                     if (src_bits && GetDIBits( screen_dc, iconinfo->hbmColor, 0, info->nHeight,
2287                                                src_bits, &bminfo, DIB_RGB_COLORS ))
2288                     {
2289                         int y;
2290                         for (y = 0; y < info->nHeight; y++)
2291                             memcpy( dst_bits + y * bitmap_width, src_bits + y * dib_width, bitmap_width );
2292                     }
2293                     HeapFree( GetProcessHeap(), 0, src_bits );
2294                 }
2295                 else
2296                     GetDIBits( screen_dc, iconinfo->hbmColor, 0, info->nHeight,
2297                                dst_bits, &bminfo, DIB_RGB_COLORS );
2298             }
2299         }
2300         GlobalUnlock16( hObj );
2301     }
2302     return HICON_32(hObj);
2303 }
2304
2305 /******************************************************************************
2306  *              DrawIconEx (USER32.@) Draws an icon or cursor on device context
2307  *
2308  * NOTES
2309  *    Why is this using SM_CXICON instead of SM_CXCURSOR?
2310  *
2311  * PARAMS
2312  *    hdc     [I] Handle to device context
2313  *    x0      [I] X coordinate of upper left corner
2314  *    y0      [I] Y coordinate of upper left corner
2315  *    hIcon   [I] Handle to icon to draw
2316  *    cxWidth [I] Width of icon
2317  *    cyWidth [I] Height of icon
2318  *    istep   [I] Index of frame in animated cursor
2319  *    hbr     [I] Handle to background brush
2320  *    flags   [I] Icon-drawing flags
2321  *
2322  * RETURNS
2323  *    Success: TRUE
2324  *    Failure: FALSE
2325  */
2326 BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
2327                             INT cxWidth, INT cyWidth, UINT istep,
2328                             HBRUSH hbr, UINT flags )
2329 {
2330     CURSORICONINFO *ptr;
2331     HDC hDC_off = 0, hMemDC;
2332     BOOL result = FALSE, DoOffscreen;
2333     HBITMAP hB_off = 0, hOld = 0;
2334     unsigned char *xorBitmapBits;
2335     unsigned int xorLength;
2336     BOOL has_alpha = FALSE;
2337
2338     TRACE_(icon)("(hdc=%p,pos=%d.%d,hicon=%p,extend=%d.%d,istep=%d,br=%p,flags=0x%08x)\n",
2339                  hdc,x0,y0,hIcon,cxWidth,cyWidth,istep,hbr,flags );
2340
2341     if (!(ptr = GlobalLock16(HICON_16(hIcon)))) return FALSE;
2342     if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
2343
2344     if (istep)
2345         FIXME_(icon)("Ignoring istep=%d\n", istep);
2346     if (flags & DI_NOMIRROR)
2347         FIXME_(icon)("Ignoring flag DI_NOMIRROR\n");
2348
2349     xorLength = ptr->nHeight * get_bitmap_width_bytes(
2350         ptr->nWidth, ptr->bBitsPerPixel);
2351     xorBitmapBits = (unsigned char *)(ptr + 1) + ptr->nHeight *
2352                     get_bitmap_width_bytes(ptr->nWidth, 1);
2353
2354     if (flags & DI_IMAGE)
2355         has_alpha = bitmap_has_alpha_channel(
2356             ptr->bBitsPerPixel, xorBitmapBits, xorLength);
2357
2358     /* Calculate the size of the destination image.  */
2359     if (cxWidth == 0)
2360     {
2361         if (flags & DI_DEFAULTSIZE)
2362             cxWidth = GetSystemMetrics (SM_CXICON);
2363         else
2364             cxWidth = ptr->nWidth;
2365     }
2366     if (cyWidth == 0)
2367     {
2368         if (flags & DI_DEFAULTSIZE)
2369             cyWidth = GetSystemMetrics (SM_CYICON);
2370         else
2371             cyWidth = ptr->nHeight;
2372     }
2373
2374     DoOffscreen = (GetObjectType( hbr ) == OBJ_BRUSH);
2375
2376     if (DoOffscreen) {
2377         RECT r;
2378
2379         r.left = 0;
2380         r.top = 0;
2381         r.right = cxWidth;
2382         r.bottom = cxWidth;
2383
2384         hDC_off = CreateCompatibleDC(hdc);
2385         hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth);
2386         if (hDC_off && hB_off) {
2387             hOld = SelectObject(hDC_off, hB_off);
2388             FillRect(hDC_off, &r, hbr);
2389         }
2390     }
2391
2392     if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
2393     {
2394         HBITMAP hBitTemp;
2395         HBITMAP hXorBits = NULL, hAndBits = NULL;
2396         COLORREF  oldFg, oldBg;
2397         INT     nStretchMode;
2398
2399         nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
2400
2401         oldFg = SetTextColor( hdc, RGB(0,0,0) );
2402         oldBg = SetBkColor( hdc, RGB(255,255,255) );
2403
2404         if (((flags & DI_MASK) && !(flags & DI_IMAGE)) ||
2405             ((flags & DI_MASK) && !has_alpha))
2406         {
2407             hAndBits = CreateBitmap ( ptr->nWidth, ptr->nHeight, 1, 1, ptr + 1 );
2408             if (hAndBits)
2409             {
2410                 hBitTemp = SelectObject( hMemDC, hAndBits );
2411                 if (DoOffscreen)
2412                     StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
2413                                 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
2414                 else
2415                     StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
2416                                 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
2417                 SelectObject( hMemDC, hBitTemp );
2418             }
2419         }
2420
2421         if (flags & DI_IMAGE)
2422         {
2423             BITMAPINFOHEADER bmih;
2424             unsigned char *dibBits;
2425
2426             memset(&bmih, 0, sizeof(BITMAPINFOHEADER));
2427             bmih.biSize = sizeof(BITMAPINFOHEADER);
2428             bmih.biWidth = ptr->nWidth;
2429             bmih.biHeight = -ptr->nHeight;
2430             bmih.biPlanes = ptr->bPlanes;
2431             bmih.biBitCount = ptr->bBitsPerPixel;
2432             bmih.biCompression = BI_RGB;
2433
2434             hXorBits = CreateDIBSection(hdc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS,
2435                                         (void*)&dibBits, NULL, 0);
2436
2437             if (hXorBits && dibBits)
2438             {
2439                 if(has_alpha)
2440                 {
2441                     BLENDFUNCTION pixelblend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
2442
2443                     /* Do the alpha blending render */
2444                     premultiply_alpha_channel(dibBits, xorBitmapBits, xorLength);
2445                     hBitTemp = SelectObject( hMemDC, hXorBits );
2446
2447                     if (DoOffscreen)
2448                         GdiAlphaBlend(hDC_off, 0, 0, cxWidth, cyWidth, hMemDC,
2449                                         0, 0, ptr->nWidth, ptr->nHeight, pixelblend);
2450                     else
2451                         GdiAlphaBlend(hdc, x0, y0, cxWidth, cyWidth, hMemDC,
2452                                         0, 0, ptr->nWidth, ptr->nHeight, pixelblend);
2453
2454                     SelectObject( hMemDC, hBitTemp );
2455                 }
2456                 else
2457                 {
2458                     memcpy(dibBits, xorBitmapBits, xorLength);
2459                     hBitTemp = SelectObject( hMemDC, hXorBits );
2460                     if (DoOffscreen)
2461                         StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
2462                                     hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
2463                     else
2464                         StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
2465                                     hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
2466                     SelectObject( hMemDC, hBitTemp );
2467                 }
2468
2469                 DeleteObject( hXorBits );
2470             }
2471         }
2472
2473         result = TRUE;
2474
2475         SetTextColor( hdc, oldFg );
2476         SetBkColor( hdc, oldBg );
2477
2478         if (hAndBits) DeleteObject( hAndBits );
2479         SetStretchBltMode (hdc, nStretchMode);
2480         if (DoOffscreen) {
2481             BitBlt(hdc, x0, y0, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
2482             SelectObject(hDC_off, hOld);
2483         }
2484     }
2485     if (hMemDC) DeleteDC( hMemDC );
2486     if (hDC_off) DeleteDC(hDC_off);
2487     if (hB_off) DeleteObject(hB_off);
2488     GlobalUnlock16(HICON_16(hIcon));
2489     return result;
2490 }
2491
2492 /***********************************************************************
2493  *           DIB_FixColorsToLoadflags
2494  *
2495  * Change color table entries when LR_LOADTRANSPARENT or LR_LOADMAP3DCOLORS
2496  * are in loadflags
2497  */
2498 static void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags, BYTE pix)
2499 {
2500     int colors;
2501     COLORREF c_W, c_S, c_F, c_L, c_C;
2502     int incr,i;
2503     RGBQUAD *ptr;
2504     int bitmap_type;
2505     LONG width;
2506     LONG height;
2507     WORD bpp;
2508     DWORD compr;
2509
2510     if (((bitmap_type = DIB_GetBitmapInfo((BITMAPINFOHEADER*) bmi, &width, &height, &bpp, &compr)) == -1))
2511     {
2512         WARN_(resource)("Invalid bitmap\n");
2513         return;
2514     }
2515
2516     if (bpp > 8) return;
2517
2518     if (bitmap_type == 0) /* BITMAPCOREHEADER */
2519     {
2520         incr = 3;
2521         colors = 1 << bpp;
2522     }
2523     else
2524     {
2525         incr = 4;
2526         colors = bmi->bmiHeader.biClrUsed;
2527         if (colors > 256) colors = 256;
2528         if (!colors && (bpp <= 8)) colors = 1 << bpp;
2529     }
2530
2531     c_W = GetSysColor(COLOR_WINDOW);
2532     c_S = GetSysColor(COLOR_3DSHADOW);
2533     c_F = GetSysColor(COLOR_3DFACE);
2534     c_L = GetSysColor(COLOR_3DLIGHT);
2535
2536     if (loadflags & LR_LOADTRANSPARENT) {
2537         switch (bpp) {
2538         case 1: pix = pix >> 7; break;
2539         case 4: pix = pix >> 4; break;
2540         case 8: break;
2541         default:
2542             WARN_(resource)("(%d): Unsupported depth\n", bpp);
2543             return;
2544         }
2545         if (pix >= colors) {
2546             WARN_(resource)("pixel has color index greater than biClrUsed!\n");
2547             return;
2548         }
2549         if (loadflags & LR_LOADMAP3DCOLORS) c_W = c_F;
2550         ptr = (RGBQUAD*)((char*)bmi->bmiColors+pix*incr);
2551         ptr->rgbBlue = GetBValue(c_W);
2552         ptr->rgbGreen = GetGValue(c_W);
2553         ptr->rgbRed = GetRValue(c_W);
2554     }
2555     if (loadflags & LR_LOADMAP3DCOLORS)
2556         for (i=0; i<colors; i++) {
2557             ptr = (RGBQUAD*)((char*)bmi->bmiColors+i*incr);
2558             c_C = RGB(ptr->rgbRed, ptr->rgbGreen, ptr->rgbBlue);
2559             if (c_C == RGB(128, 128, 128)) {
2560                 ptr->rgbRed = GetRValue(c_S);
2561                 ptr->rgbGreen = GetGValue(c_S);
2562                 ptr->rgbBlue = GetBValue(c_S);
2563             } else if (c_C == RGB(192, 192, 192)) {
2564                 ptr->rgbRed = GetRValue(c_F);
2565                 ptr->rgbGreen = GetGValue(c_F);
2566                 ptr->rgbBlue = GetBValue(c_F);
2567             } else if (c_C == RGB(223, 223, 223)) {
2568                 ptr->rgbRed = GetRValue(c_L);
2569                 ptr->rgbGreen = GetGValue(c_L);
2570                 ptr->rgbBlue = GetBValue(c_L);
2571             }
2572         }
2573 }
2574
2575
2576 /**********************************************************************
2577  *       BITMAP_Load
2578  */
2579 static HBITMAP BITMAP_Load( HINSTANCE instance, LPCWSTR name,
2580                             INT desiredx, INT desiredy, UINT loadflags )
2581 {
2582     HBITMAP hbitmap = 0, orig_bm;
2583     HRSRC hRsrc;
2584     HGLOBAL handle;
2585     char *ptr = NULL;
2586     BITMAPINFO *info, *fix_info = NULL, *scaled_info = NULL;
2587     int size;
2588     BYTE pix;
2589     char *bits;
2590     LONG width, height, new_width, new_height;
2591     WORD bpp_dummy;
2592     DWORD compr_dummy;
2593     INT bm_type;
2594     HDC screen_mem_dc = NULL;
2595
2596     if (!(loadflags & LR_LOADFROMFILE))
2597     {
2598         if (!instance)
2599         {
2600             /* OEM bitmap: try to load the resource from user32.dll */
2601             instance = user32_module;
2602         }
2603
2604         if (!(hRsrc = FindResourceW( instance, name, (LPWSTR)RT_BITMAP ))) return 0;
2605         if (!(handle = LoadResource( instance, hRsrc ))) return 0;
2606
2607         if ((info = LockResource( handle )) == NULL) return 0;
2608     }
2609     else
2610     {
2611         BITMAPFILEHEADER * bmfh;
2612
2613         if (!(ptr = map_fileW( name, NULL ))) return 0;
2614         info = (BITMAPINFO *)(ptr + sizeof(BITMAPFILEHEADER));
2615         bmfh = (BITMAPFILEHEADER *)ptr;
2616         if (!(  bmfh->bfType == 0x4d42 /* 'BM' */ &&
2617                 bmfh->bfReserved1 == 0 &&
2618                 bmfh->bfReserved2 == 0))
2619         {
2620             WARN("Invalid/unsupported bitmap format!\n");
2621             UnmapViewOfFile( ptr );
2622             return 0;
2623         }
2624     }
2625
2626     size = bitmap_info_size(info, DIB_RGB_COLORS);
2627     fix_info = HeapAlloc(GetProcessHeap(), 0, size);
2628     scaled_info = HeapAlloc(GetProcessHeap(), 0, size);
2629
2630     if (!fix_info || !scaled_info) goto end;
2631     memcpy(fix_info, info, size);
2632
2633     pix = *((LPBYTE)info + size);
2634     DIB_FixColorsToLoadflags(fix_info, loadflags, pix);
2635
2636     memcpy(scaled_info, fix_info, size);
2637     bm_type = DIB_GetBitmapInfo( &fix_info->bmiHeader, &width, &height,
2638                                  &bpp_dummy, &compr_dummy);
2639     if(desiredx != 0)
2640         new_width = desiredx;
2641     else
2642         new_width = width;
2643
2644     if(desiredy != 0)
2645         new_height = height > 0 ? desiredy : -desiredy;
2646     else
2647         new_height = height;
2648
2649     if(bm_type == 0)
2650     {
2651         BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)&scaled_info->bmiHeader;
2652         core->bcWidth = new_width;
2653         core->bcHeight = new_height;
2654     }
2655     else
2656     {
2657         scaled_info->bmiHeader.biWidth = new_width;
2658         scaled_info->bmiHeader.biHeight = new_height;
2659     }
2660
2661     if (new_height < 0) new_height = -new_height;
2662
2663     if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
2664     if (!(screen_mem_dc = CreateCompatibleDC( screen_dc ))) goto end;
2665
2666     bits = (char *)info + size;
2667
2668     if (loadflags & LR_CREATEDIBSECTION)
2669     {
2670         scaled_info->bmiHeader.biCompression = 0; /* DIBSection can't be compressed */
2671         hbitmap = CreateDIBSection(screen_dc, scaled_info, DIB_RGB_COLORS, NULL, 0, 0);
2672     }
2673     else
2674     {
2675         if (is_dib_monochrome(fix_info))
2676             hbitmap = CreateBitmap(new_width, new_height, 1, 1, NULL);
2677         else
2678             hbitmap = CreateCompatibleBitmap(screen_dc, new_width, new_height);        
2679     }
2680
2681     orig_bm = SelectObject(screen_mem_dc, hbitmap);
2682     StretchDIBits(screen_mem_dc, 0, 0, new_width, new_height, 0, 0, width, height, bits, fix_info, DIB_RGB_COLORS, SRCCOPY);
2683     SelectObject(screen_mem_dc, orig_bm);
2684
2685 end:
2686     if (screen_mem_dc) DeleteDC(screen_mem_dc);
2687     HeapFree(GetProcessHeap(), 0, scaled_info);
2688     HeapFree(GetProcessHeap(), 0, fix_info);
2689     if (loadflags & LR_LOADFROMFILE) UnmapViewOfFile( ptr );
2690
2691     return hbitmap;
2692 }
2693
2694 /**********************************************************************
2695  *              LoadImageA (USER32.@)
2696  *
2697  * See LoadImageW.
2698  */
2699 HANDLE WINAPI LoadImageA( HINSTANCE hinst, LPCSTR name, UINT type,
2700                               INT desiredx, INT desiredy, UINT loadflags)
2701 {
2702     HANDLE res;
2703     LPWSTR u_name;
2704
2705     if (!HIWORD(name))
2706         return LoadImageW(hinst, (LPCWSTR)name, type, desiredx, desiredy, loadflags);
2707
2708     __TRY {
2709         DWORD len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
2710         u_name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2711         MultiByteToWideChar( CP_ACP, 0, name, -1, u_name, len );
2712     }
2713     __EXCEPT_PAGE_FAULT {
2714         SetLastError( ERROR_INVALID_PARAMETER );
2715         return 0;
2716     }
2717     __ENDTRY
2718     res = LoadImageW(hinst, u_name, type, desiredx, desiredy, loadflags);
2719     HeapFree(GetProcessHeap(), 0, u_name);
2720     return res;
2721 }
2722
2723
2724 /******************************************************************************
2725  *              LoadImageW (USER32.@) Loads an icon, cursor, or bitmap
2726  *
2727  * PARAMS
2728  *    hinst     [I] Handle of instance that contains image
2729  *    name      [I] Name of image
2730  *    type      [I] Type of image
2731  *    desiredx  [I] Desired width
2732  *    desiredy  [I] Desired height
2733  *    loadflags [I] Load flags
2734  *
2735  * RETURNS
2736  *    Success: Handle to newly loaded image
2737  *    Failure: NULL
2738  *
2739  * FIXME: Implementation lacks some features, see LR_ defines in winuser.h
2740  */
2741 HANDLE WINAPI LoadImageW( HINSTANCE hinst, LPCWSTR name, UINT type,
2742                 INT desiredx, INT desiredy, UINT loadflags )
2743 {
2744     TRACE_(resource)("(%p,%s,%d,%d,%d,0x%08x)\n",
2745                      hinst,debugstr_w(name),type,desiredx,desiredy,loadflags);
2746
2747     if (loadflags & LR_DEFAULTSIZE) {
2748         if (type == IMAGE_ICON) {
2749             if (!desiredx) desiredx = GetSystemMetrics(SM_CXICON);
2750             if (!desiredy) desiredy = GetSystemMetrics(SM_CYICON);
2751         } else if (type == IMAGE_CURSOR) {
2752             if (!desiredx) desiredx = GetSystemMetrics(SM_CXCURSOR);
2753             if (!desiredy) desiredy = GetSystemMetrics(SM_CYCURSOR);
2754         }
2755     }
2756     if (loadflags & LR_LOADFROMFILE) loadflags &= ~LR_SHARED;
2757     switch (type) {
2758     case IMAGE_BITMAP:
2759         return BITMAP_Load( hinst, name, desiredx, desiredy, loadflags );
2760
2761     case IMAGE_ICON:
2762         if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
2763         if (screen_dc)
2764         {
2765             UINT palEnts = GetSystemPaletteEntries(screen_dc, 0, 0, NULL);
2766             if (palEnts == 0) palEnts = 256;
2767             return CURSORICON_Load(hinst, name, desiredx, desiredy,
2768                                    palEnts, FALSE, loadflags);
2769         }
2770         break;
2771
2772     case IMAGE_CURSOR:
2773         return CURSORICON_Load(hinst, name, desiredx, desiredy,
2774                                1, TRUE, loadflags);
2775     }
2776     return 0;
2777 }
2778
2779 /******************************************************************************
2780  *              CopyImage (USER32.@) Creates new image and copies attributes to it
2781  *
2782  * PARAMS
2783  *    hnd      [I] Handle to image to copy
2784  *    type     [I] Type of image to copy
2785  *    desiredx [I] Desired width of new image
2786  *    desiredy [I] Desired height of new image
2787  *    flags    [I] Copy flags
2788  *
2789  * RETURNS
2790  *    Success: Handle to newly created image
2791  *    Failure: NULL
2792  *
2793  * BUGS
2794  *    Only Windows NT 4.0 supports the LR_COPYRETURNORG flag for bitmaps,
2795  *    all other versions (95/2000/XP have been tested) ignore it.
2796  *
2797  * NOTES
2798  *    If LR_CREATEDIBSECTION is absent, the copy will be monochrome for
2799  *    a monochrome source bitmap or if LR_MONOCHROME is present, otherwise
2800  *    the copy will have the same depth as the screen.
2801  *    The content of the image will only be copied if the bit depth of the
2802  *    original image is compatible with the bit depth of the screen, or
2803  *    if the source is a DIB section.
2804  *    The LR_MONOCHROME flag is ignored if LR_CREATEDIBSECTION is present.
2805  */
2806 HANDLE WINAPI CopyImage( HANDLE hnd, UINT type, INT desiredx,
2807                              INT desiredy, UINT flags )
2808 {
2809     TRACE("hnd=%p, type=%u, desiredx=%d, desiredy=%d, flags=%x\n",
2810           hnd, type, desiredx, desiredy, flags);
2811
2812     switch (type)
2813     {
2814         case IMAGE_BITMAP:
2815         {
2816             HBITMAP res = NULL;
2817             DIBSECTION ds;
2818             int objSize;
2819             BITMAPINFO * bi;
2820
2821             objSize = GetObjectW( hnd, sizeof(ds), &ds );
2822             if (!objSize) return 0;
2823             if ((desiredx < 0) || (desiredy < 0)) return 0;
2824
2825             if (flags & LR_COPYFROMRESOURCE)
2826             {
2827                 FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
2828             }
2829
2830             if (desiredx == 0) desiredx = ds.dsBm.bmWidth;
2831             if (desiredy == 0) desiredy = ds.dsBm.bmHeight;
2832
2833             /* Allocate memory for a BITMAPINFOHEADER structure and a
2834                color table. The maximum number of colors in a color table
2835                is 256 which corresponds to a bitmap with depth 8.
2836                Bitmaps with higher depths don't have color tables. */
2837             bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2838             if (!bi) return 0;
2839
2840             bi->bmiHeader.biSize        = sizeof(bi->bmiHeader);
2841             bi->bmiHeader.biPlanes      = ds.dsBm.bmPlanes;
2842             bi->bmiHeader.biBitCount    = ds.dsBm.bmBitsPixel;
2843             bi->bmiHeader.biCompression = BI_RGB;
2844
2845             if (flags & LR_CREATEDIBSECTION)
2846             {
2847                 /* Create a DIB section. LR_MONOCHROME is ignored */
2848                 void * bits;
2849                 HDC dc = CreateCompatibleDC(NULL);
2850
2851                 if (objSize == sizeof(DIBSECTION))
2852                 {
2853                     /* The source bitmap is a DIB.
2854                        Get its attributes to create an exact copy */
2855                     memcpy(bi, &ds.dsBmih, sizeof(BITMAPINFOHEADER));
2856                 }
2857
2858                 /* Get the color table or the color masks */
2859                 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
2860
2861                 bi->bmiHeader.biWidth  = desiredx;
2862                 bi->bmiHeader.biHeight = desiredy;
2863                 bi->bmiHeader.biSizeImage = 0;
2864
2865                 res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
2866                 DeleteDC(dc);
2867             }
2868             else
2869             {
2870                 /* Create a device-dependent bitmap */
2871
2872                 BOOL monochrome = (flags & LR_MONOCHROME);
2873
2874                 if (objSize == sizeof(DIBSECTION))
2875                 {
2876                     /* The source bitmap is a DIB section.
2877                        Get its attributes */
2878                     HDC dc = CreateCompatibleDC(NULL);
2879                     bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
2880                     bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
2881                     GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
2882                     DeleteDC(dc);
2883
2884                     if (!monochrome && ds.dsBm.bmBitsPixel == 1)
2885                     {
2886                         /* Look if the colors of the DIB are black and white */
2887
2888                         monochrome = 
2889                               (bi->bmiColors[0].rgbRed == 0xff
2890                             && bi->bmiColors[0].rgbGreen == 0xff
2891                             && bi->bmiColors[0].rgbBlue == 0xff
2892                             && bi->bmiColors[0].rgbReserved == 0
2893                             && bi->bmiColors[1].rgbRed == 0
2894                             && bi->bmiColors[1].rgbGreen == 0
2895                             && bi->bmiColors[1].rgbBlue == 0
2896                             && bi->bmiColors[1].rgbReserved == 0)
2897                             ||
2898                               (bi->bmiColors[0].rgbRed == 0
2899                             && bi->bmiColors[0].rgbGreen == 0
2900                             && bi->bmiColors[0].rgbBlue == 0
2901                             && bi->bmiColors[0].rgbReserved == 0
2902                             && bi->bmiColors[1].rgbRed == 0xff
2903                             && bi->bmiColors[1].rgbGreen == 0xff
2904                             && bi->bmiColors[1].rgbBlue == 0xff
2905                             && bi->bmiColors[1].rgbReserved == 0);
2906                     }
2907                 }
2908                 else if (!monochrome)
2909                 {
2910                     monochrome = ds.dsBm.bmBitsPixel == 1;
2911                 }
2912
2913                 if (monochrome)
2914                 {
2915                     res = CreateBitmap(desiredx, desiredy, 1, 1, NULL);
2916                 }
2917                 else
2918                 {
2919                     HDC screenDC = GetDC(NULL);
2920                     res = CreateCompatibleBitmap(screenDC, desiredx, desiredy);
2921                     ReleaseDC(NULL, screenDC);
2922                 }
2923             }
2924
2925             if (res)
2926             {
2927                 /* Only copy the bitmap if it's a DIB section or if it's
2928                    compatible to the screen */
2929                 BOOL copyContents;
2930
2931                 if (objSize == sizeof(DIBSECTION))
2932                 {
2933                     copyContents = TRUE;
2934                 }
2935                 else
2936                 {
2937                     HDC screenDC = GetDC(NULL);
2938                     int screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
2939                     ReleaseDC(NULL, screenDC);
2940
2941                     copyContents = (ds.dsBm.bmBitsPixel == 1 || ds.dsBm.bmBitsPixel == screen_depth);
2942                 }
2943
2944                 if (copyContents)
2945                 {
2946                     /* The source bitmap may already be selected in a device context,
2947                        use GetDIBits/StretchDIBits and not StretchBlt  */
2948
2949                     HDC dc;
2950                     void * bits;
2951
2952                     dc = CreateCompatibleDC(NULL);
2953
2954                     bi->bmiHeader.biWidth = ds.dsBm.bmWidth;
2955                     bi->bmiHeader.biHeight = ds.dsBm.bmHeight;
2956                     bi->bmiHeader.biSizeImage = 0;
2957                     bi->bmiHeader.biClrUsed = 0;
2958                     bi->bmiHeader.biClrImportant = 0;
2959
2960                     /* Fill in biSizeImage */
2961                     GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
2962                     bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bi->bmiHeader.biSizeImage);
2963
2964                     if (bits)
2965                     {
2966                         HBITMAP oldBmp;
2967
2968                         /* Get the image bits of the source bitmap */
2969                         GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS);
2970
2971                         /* Copy it to the destination bitmap */
2972                         oldBmp = SelectObject(dc, res);
2973                         StretchDIBits(dc, 0, 0, desiredx, desiredy,
2974                                       0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight,
2975                                       bits, bi, DIB_RGB_COLORS, SRCCOPY);
2976                         SelectObject(dc, oldBmp);
2977
2978                         HeapFree(GetProcessHeap(), 0, bits);
2979                     }
2980
2981                     DeleteDC(dc);
2982                 }
2983
2984                 if (flags & LR_COPYDELETEORG)
2985                 {
2986                     DeleteObject(hnd);
2987                 }
2988             }
2989             HeapFree(GetProcessHeap(), 0, bi);
2990             return res;
2991         }
2992         case IMAGE_ICON:
2993                 return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags);
2994         case IMAGE_CURSOR:
2995                 /* Should call CURSORICON_ExtCopy but more testing
2996                  * needs to be done before we change this
2997                  */
2998                 if (flags) FIXME("Flags are ignored\n");
2999                 return CopyCursor(hnd);
3000     }
3001     return 0;
3002 }
3003
3004
3005 /******************************************************************************
3006  *              LoadBitmapW (USER32.@) Loads bitmap from the executable file
3007  *
3008  * RETURNS
3009  *    Success: Handle to specified bitmap
3010  *    Failure: NULL
3011  */
3012 HBITMAP WINAPI LoadBitmapW(
3013     HINSTANCE instance, /* [in] Handle to application instance */
3014     LPCWSTR name)         /* [in] Address of bitmap resource name */
3015 {
3016     return LoadImageW( instance, name, IMAGE_BITMAP, 0, 0, 0 );
3017 }
3018
3019 /**********************************************************************
3020  *              LoadBitmapA (USER32.@)
3021  *
3022  * See LoadBitmapW.
3023  */
3024 HBITMAP WINAPI LoadBitmapA( HINSTANCE instance, LPCSTR name )
3025 {
3026     return LoadImageA( instance, name, IMAGE_BITMAP, 0, 0, 0 );
3027 }