[02/10] user: Create 32-bit cursor handles
[wine/hacks.git] / dlls / user32 / cursoricon.c
blobbb5dcdff1ad3bde3a1a6d10bbb8a4cccf9512b5f
1 /*
2 * Cursor and icon support
4 * Copyright 1995 Alexandre Julliard
5 * 1996 Martin Von Loewis
6 * 1997 Alex Korobka
7 * 1998 Turchanov Sergey
8 * 2007 Henri Verbeet
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.
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.
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
26 * Theory:
28 * Cursors and icons are stored in a global heap block, with the
29 * following layout:
31 * CURSORICONINFO info;
32 * BYTE[] ANDbits;
33 * BYTE[] XORbits;
35 * The bits structures are in the format of a device-dependent bitmap.
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 :-(
43 #include "config.h"
44 #include "wine/port.h"
46 #include <stdarg.h>
47 #include <string.h>
48 #include <stdlib.h>
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 "wine/list.h"
59 #include "wine/server.h"
60 #include "user_private.h"
62 WINE_DEFAULT_DEBUG_CHANNEL(cursor);
63 WINE_DECLARE_DEBUG_CHANNEL(icon);
64 WINE_DECLARE_DEBUG_CHANNEL(resource);
66 #include "pshpack1.h"
68 typedef struct {
69 BYTE bWidth;
70 BYTE bHeight;
71 BYTE bColorCount;
72 BYTE bReserved;
73 WORD xHotspot;
74 WORD yHotspot;
75 DWORD dwDIBSize;
76 DWORD dwDIBOffset;
77 } CURSORICONFILEDIRENTRY;
79 typedef struct
81 WORD idReserved;
82 WORD idType;
83 WORD idCount;
84 CURSORICONFILEDIRENTRY idEntries[1];
85 } CURSORICONFILEDIR;
87 #include "poppack.h"
89 #define CID_RESOURCE 0x0001
90 #define CID_WIN32 0x0004
91 #define CID_NONSHARED 0x0008
93 static RECT CURSOR_ClipRect; /* Cursor clipping rect */
95 static HDC screen_dc;
97 static const WCHAR DISPLAYW[] = {'D','I','S','P','L','A','Y',0};
99 /**********************************************************************
100 * ICONCACHE for cursors/icons loaded with LR_SHARED.
102 * FIXME: This should not be allocated on the system heap, but on a
103 * subsystem-global heap (i.e. one for all Win16 processes,
104 * and one for each Win32 process).
106 typedef struct tagICONCACHE
108 struct tagICONCACHE *next;
110 HMODULE hModule;
111 HRSRC hRsrc;
112 HRSRC hGroupRsrc;
113 HICON hIcon;
115 INT count;
117 } ICONCACHE;
119 static ICONCACHE *IconAnchor = NULL;
121 static CRITICAL_SECTION IconCrst;
122 static CRITICAL_SECTION_DEBUG critsect_debug =
124 0, 0, &IconCrst,
125 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
126 0, 0, { (DWORD_PTR)(__FILE__ ": IconCrst") }
128 static CRITICAL_SECTION IconCrst = { &critsect_debug, -1, 0, 0, 0, 0 };
130 static const WORD ICON_HOTSPOT = 0x4242;
132 /* What is a good table size? */
133 #define CURSOR_HASH_SIZE 97
135 typedef struct {
136 HCURSOR16 cursor16;
137 HCURSOR cursor32;
138 struct list entry16;
139 struct list entry32;
140 } cursor_map_entry_t;
142 static struct list cursor16to32[CURSOR_HASH_SIZE];
143 static struct list cursor32to16[CURSOR_HASH_SIZE];
145 static inline int hash_cursor_handle( DWORD handle )
147 return handle % CURSOR_HASH_SIZE;
150 static void add_cursor16to32_entry( cursor_map_entry_t *entry )
152 int idx = hash_cursor_handle( entry->cursor16 );
154 if (!cursor16to32[idx].next) list_init( &cursor16to32[idx] );
156 list_add_head( &cursor16to32[idx], &entry->entry16 );
159 static void add_cursor32to16_entry( cursor_map_entry_t *entry )
161 int idx = hash_cursor_handle( (DWORD)entry->cursor32 );
163 if (!cursor32to16[idx].next) list_init( &cursor32to16[idx] );
165 list_add_head( &cursor32to16[idx], &entry->entry32 );
168 static cursor_map_entry_t *remove_cursor16to32_entry( HCURSOR16 cursor16 )
170 cursor_map_entry_t *entry = NULL;
171 int idx = hash_cursor_handle( cursor16 );
173 if (cursor16to32[idx].next)
175 LIST_FOR_EACH_ENTRY( entry, &cursor16to32[idx], cursor_map_entry_t, entry16 )
176 if (entry->cursor16 == cursor16)
178 list_remove( &entry->entry16 );
179 return entry;
183 return entry;
186 static cursor_map_entry_t *remove_cursor32to16_entry( HCURSOR cursor32 )
188 cursor_map_entry_t *entry = NULL;
189 int idx = hash_cursor_handle( (DWORD)cursor32 );
191 if (cursor32to16[idx].next)
193 LIST_FOR_EACH_ENTRY( entry, &cursor32to16[idx], cursor_map_entry_t, entry32 )
194 if (entry->cursor32 == cursor32)
196 list_remove( &entry->entry32 );
197 return entry;
201 return entry;
204 static HCURSOR create_cursor( unsigned int num_frames, unsigned int delay, HCURSOR16 cursor16 )
206 HCURSOR cursor = 0;
208 SERVER_START_REQ(create_cursor)
210 req->num_frames = num_frames;
211 req->delay = delay;
212 if (!wine_server_call_err( req )) cursor = reply->handle;
214 SERVER_END_REQ;
216 if (cursor)
218 cursor_map_entry_t *entry = HeapAlloc( GetProcessHeap(), 0, sizeof(cursor_map_entry_t) );
219 entry->cursor16 = cursor16;
220 entry->cursor32 = cursor;
222 add_cursor16to32_entry( entry );
223 add_cursor32to16_entry( entry );
226 return cursor;
229 static HCURSOR16 destroy_cursor( HCURSOR cursor )
231 cursor_map_entry_t *entry;
232 HCURSOR16 cursor16 = 0;
234 if (!cursor) return 0;
236 SERVER_START_REQ(destroy_cursor)
238 req->handle = cursor;
239 wine_server_call( req );
241 SERVER_END_REQ;
243 entry = remove_cursor32to16_entry( cursor );
244 if (entry)
246 cursor16 = entry->cursor16;
247 remove_cursor16to32_entry( cursor16 );
248 HeapFree( GetProcessHeap(), 0, entry );
251 return GlobalFree16( cursor16 );
254 HCURSOR16 get_cursor_handle16( HCURSOR cursor32 )
256 cursor_map_entry_t *entry;
257 int idx = hash_cursor_handle( (DWORD)cursor32 );
259 if (!cursor32) return 0;
261 if (cursor32to16[idx].next)
263 LIST_FOR_EACH_ENTRY( entry, &cursor32to16[idx], cursor_map_entry_t, entry32 )
264 if (entry->cursor32 == cursor32) return entry->cursor16;
267 return 0;
270 HCURSOR get_cursor_handle32( HCURSOR16 cursor16 )
272 cursor_map_entry_t *entry;
273 int idx = hash_cursor_handle( cursor16 );
275 if (!cursor16) return 0;
277 if (cursor16to32[idx].next)
279 LIST_FOR_EACH_ENTRY( entry, &cursor16to32[idx], cursor_map_entry_t, entry16 )
280 if (entry->cursor16 == cursor16) return entry->cursor32;
283 return 0;
286 /***********************************************************************
287 * map_fileW
289 * Helper function to map a file to memory:
290 * name - file name
291 * [RETURN] ptr - pointer to mapped file
292 * [RETURN] filesize - pointer size of file to be stored if not NULL
294 static void *map_fileW( LPCWSTR name, LPDWORD filesize )
296 HANDLE hFile, hMapping;
297 LPVOID ptr = NULL;
299 hFile = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL,
300 OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0 );
301 if (hFile != INVALID_HANDLE_VALUE)
303 hMapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
304 if (hMapping)
306 ptr = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
307 CloseHandle( hMapping );
308 if (filesize)
309 *filesize = GetFileSize( hFile, NULL );
311 CloseHandle( hFile );
313 return ptr;
317 /***********************************************************************
318 * get_bitmap_width_bytes
320 * Return number of bytes taken by a scanline of 16-bit aligned Windows DDB
321 * data.
323 static int get_bitmap_width_bytes( int width, int bpp )
325 switch(bpp)
327 case 1:
328 return 2 * ((width+15) / 16);
329 case 4:
330 return 2 * ((width+3) / 4);
331 case 24:
332 width *= 3;
333 /* fall through */
334 case 8:
335 return width + (width & 1);
336 case 16:
337 case 15:
338 return width * 2;
339 case 32:
340 return width * 4;
341 default:
342 WARN("Unknown depth %d, please report.\n", bpp );
344 return -1;
348 /***********************************************************************
349 * get_dib_width_bytes
351 * Return the width of a DIB bitmap in bytes. DIB bitmap data is 32-bit aligned.
353 static int get_dib_width_bytes( int width, int depth )
355 int words;
357 switch(depth)
359 case 1: words = (width + 31) / 32; break;
360 case 4: words = (width + 7) / 8; break;
361 case 8: words = (width + 3) / 4; break;
362 case 15:
363 case 16: words = (width + 1) / 2; break;
364 case 24: words = (width * 3 + 3)/4; break;
365 default:
366 WARN("(%d): Unsupported depth\n", depth );
367 /* fall through */
368 case 32:
369 words = width;
371 return 4 * words;
375 /***********************************************************************
376 * bitmap_info_size
378 * Return the size of the bitmap info structure including color table.
380 static int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
382 int colors, masks = 0;
384 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
386 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
387 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
388 return sizeof(BITMAPCOREHEADER) + colors *
389 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
391 else /* assume BITMAPINFOHEADER */
393 colors = info->bmiHeader.biClrUsed;
394 if (colors > 256) /* buffer overflow otherwise */
395 colors = 256;
396 if (!colors && (info->bmiHeader.biBitCount <= 8))
397 colors = 1 << info->bmiHeader.biBitCount;
398 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
399 return sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) + colors *
400 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
405 /***********************************************************************
406 * is_dib_monochrome
408 * Returns whether a DIB can be converted to a monochrome DDB.
410 * A DIB can be converted if its color table contains only black and
411 * white. Black must be the first color in the color table.
413 * Note : If the first color in the color table is white followed by
414 * black, we can't convert it to a monochrome DDB with
415 * SetDIBits, because black and white would be inverted.
417 static BOOL is_dib_monochrome( const BITMAPINFO* info )
419 if (info->bmiHeader.biBitCount != 1) return FALSE;
421 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
423 const RGBTRIPLE *rgb = ((const BITMAPCOREINFO*)info)->bmciColors;
425 /* Check if the first color is black */
426 if ((rgb->rgbtRed == 0) && (rgb->rgbtGreen == 0) && (rgb->rgbtBlue == 0))
428 rgb++;
430 /* Check if the second color is white */
431 return ((rgb->rgbtRed == 0xff) && (rgb->rgbtGreen == 0xff)
432 && (rgb->rgbtBlue == 0xff));
434 else return FALSE;
436 else /* assume BITMAPINFOHEADER */
438 const RGBQUAD *rgb = info->bmiColors;
440 /* Check if the first color is black */
441 if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) &&
442 (rgb->rgbBlue == 0) && (rgb->rgbReserved == 0))
444 rgb++;
446 /* Check if the second color is white */
447 return ((rgb->rgbRed == 0xff) && (rgb->rgbGreen == 0xff)
448 && (rgb->rgbBlue == 0xff) && (rgb->rgbReserved == 0));
450 else return FALSE;
454 /***********************************************************************
455 * DIB_GetBitmapInfo
457 * Get the info from a bitmap header.
458 * Return 1 for INFOHEADER, 0 for COREHEADER,
459 * 4 for V4HEADER, 5 for V5HEADER, -1 for error.
461 static int DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width,
462 LONG *height, WORD *bpp, DWORD *compr )
464 if (header->biSize == sizeof(BITMAPINFOHEADER))
466 *width = header->biWidth;
467 *height = header->biHeight;
468 *bpp = header->biBitCount;
469 *compr = header->biCompression;
470 return 1;
472 if (header->biSize == sizeof(BITMAPCOREHEADER))
474 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header;
475 *width = core->bcWidth;
476 *height = core->bcHeight;
477 *bpp = core->bcBitCount;
478 *compr = 0;
479 return 0;
481 if (header->biSize == sizeof(BITMAPV4HEADER))
483 const BITMAPV4HEADER *v4hdr = (const BITMAPV4HEADER *)header;
484 *width = v4hdr->bV4Width;
485 *height = v4hdr->bV4Height;
486 *bpp = v4hdr->bV4BitCount;
487 *compr = v4hdr->bV4V4Compression;
488 return 4;
490 if (header->biSize == sizeof(BITMAPV5HEADER))
492 const BITMAPV5HEADER *v5hdr = (const BITMAPV5HEADER *)header;
493 *width = v5hdr->bV5Width;
494 *height = v5hdr->bV5Height;
495 *bpp = v5hdr->bV5BitCount;
496 *compr = v5hdr->bV5Compression;
497 return 5;
499 ERR("(%d): unknown/wrong size for header\n", header->biSize );
500 return -1;
503 /**********************************************************************
504 * CURSORICON_FindSharedIcon
506 static HICON CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
508 HICON hIcon = 0;
509 ICONCACHE *ptr;
511 EnterCriticalSection( &IconCrst );
513 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
514 if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
516 ptr->count++;
517 hIcon = ptr->hIcon;
518 break;
521 LeaveCriticalSection( &IconCrst );
523 return hIcon;
526 /*************************************************************************
527 * CURSORICON_FindCache
529 * Given a handle, find the corresponding cache element
531 * PARAMS
532 * Handle [I] handle to an Image
534 * RETURNS
535 * Success: The cache entry
536 * Failure: NULL
539 static ICONCACHE* CURSORICON_FindCache(HICON hIcon)
541 ICONCACHE *ptr;
542 ICONCACHE *pRet=NULL;
543 BOOL IsFound = FALSE;
545 EnterCriticalSection( &IconCrst );
547 for (ptr = IconAnchor; ptr != NULL && !IsFound; ptr = ptr->next)
549 if ( hIcon == ptr->hIcon )
551 IsFound = TRUE;
552 pRet = ptr;
556 LeaveCriticalSection( &IconCrst );
558 return pRet;
561 /**********************************************************************
562 * CURSORICON_AddSharedIcon
564 static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HRSRC hGroupRsrc, HICON hIcon )
566 ICONCACHE *ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(ICONCACHE) );
567 if ( !ptr ) return;
569 ptr->hModule = hModule;
570 ptr->hRsrc = hRsrc;
571 ptr->hIcon = hIcon;
572 ptr->hGroupRsrc = hGroupRsrc;
573 ptr->count = 1;
575 EnterCriticalSection( &IconCrst );
576 ptr->next = IconAnchor;
577 IconAnchor = ptr;
578 LeaveCriticalSection( &IconCrst );
581 /**********************************************************************
582 * CURSORICON_DelSharedIcon
584 static INT CURSORICON_DelSharedIcon( HICON hIcon )
586 INT count = -1;
587 ICONCACHE *ptr;
589 EnterCriticalSection( &IconCrst );
591 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
592 if ( ptr->hIcon == hIcon )
594 if ( ptr->count > 0 ) ptr->count--;
595 count = ptr->count;
596 break;
599 LeaveCriticalSection( &IconCrst );
601 return count;
604 /**********************************************************************
605 * CURSORICON_FreeModuleIcons
607 void CURSORICON_FreeModuleIcons( HMODULE16 hMod16 )
609 ICONCACHE **ptr = &IconAnchor;
610 HMODULE hModule = HMODULE_32(GetExePtr( hMod16 ));
612 EnterCriticalSection( &IconCrst );
614 while ( *ptr )
616 if ( (*ptr)->hModule == hModule )
618 ICONCACHE *freePtr = *ptr;
619 *ptr = freePtr->next;
621 destroy_cursor( freePtr->hIcon );
622 HeapFree( GetProcessHeap(), 0, freePtr );
623 continue;
625 ptr = &(*ptr)->next;
628 LeaveCriticalSection( &IconCrst );
632 * The following macro functions account for the irregularities of
633 * accessing cursor and icon resources in files and resource entries.
635 typedef BOOL (*fnGetCIEntry)( LPVOID dir, int n,
636 int *width, int *height, int *bits );
638 /**********************************************************************
639 * CURSORICON_FindBestIcon
641 * Find the icon closest to the requested size and number of colors.
643 static int CURSORICON_FindBestIcon( LPVOID dir, fnGetCIEntry get_entry,
644 int width, int height, int colors )
646 int i, cx, cy, bits, bestEntry = -1;
647 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
648 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
650 /* Find Best Fit */
651 iTotalDiff = 0xFFFFFFFF;
652 iColorDiff = 0xFFFFFFFF;
653 for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
655 iTempXDiff = abs(width - cx);
656 iTempYDiff = abs(height - cy);
658 if(iTotalDiff > (iTempXDiff + iTempYDiff))
660 iXDiff = iTempXDiff;
661 iYDiff = iTempYDiff;
662 iTotalDiff = iXDiff + iYDiff;
666 /* Find Best Colors for Best Fit */
667 for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
669 if(abs(width - cx) == iXDiff && abs(height - cy) == iYDiff)
671 iTempColorDiff = abs(colors - (1<<bits));
672 if(iColorDiff > iTempColorDiff)
674 bestEntry = i;
675 iColorDiff = iTempColorDiff;
680 return bestEntry;
683 static BOOL CURSORICON_GetResIconEntry( LPVOID dir, int n,
684 int *width, int *height, int *bits )
686 CURSORICONDIR *resdir = dir;
687 ICONRESDIR *icon;
689 if ( resdir->idCount <= n )
690 return FALSE;
691 icon = &resdir->idEntries[n].ResInfo.icon;
692 *width = icon->bWidth;
693 *height = icon->bHeight;
694 *bits = resdir->idEntries[n].wBitCount;
695 return TRUE;
698 /**********************************************************************
699 * CURSORICON_FindBestCursor
701 * Find the cursor closest to the requested size.
702 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
703 * ignored too
705 static int CURSORICON_FindBestCursor( LPVOID dir, fnGetCIEntry get_entry,
706 int width, int height, int color )
708 int i, maxwidth, maxheight, cx, cy, bits, bestEntry = -1;
710 /* Double height to account for AND and XOR masks */
712 height *= 2;
714 /* First find the largest one smaller than or equal to the requested size*/
716 maxwidth = maxheight = 0;
717 for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
719 if ((cx <= width) && (cy <= height) &&
720 (cx > maxwidth) && (cy > maxheight) &&
721 (bits == 1))
723 bestEntry = i;
724 maxwidth = cx;
725 maxheight = cy;
728 if (bestEntry != -1) return bestEntry;
730 /* Now find the smallest one larger than the requested size */
732 maxwidth = maxheight = 255;
733 for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
735 if (((cx < maxwidth) && (cy < maxheight) && (bits == 1)) ||
736 (bestEntry==-1))
738 bestEntry = i;
739 maxwidth = cx;
740 maxheight = cy;
744 return bestEntry;
747 static BOOL CURSORICON_GetResCursorEntry( LPVOID dir, int n,
748 int *width, int *height, int *bits )
750 CURSORICONDIR *resdir = dir;
751 CURSORDIR *cursor;
753 if ( resdir->idCount <= n )
754 return FALSE;
755 cursor = &resdir->idEntries[n].ResInfo.cursor;
756 *width = cursor->wWidth;
757 *height = cursor->wHeight;
758 *bits = resdir->idEntries[n].wBitCount;
759 return TRUE;
762 static CURSORICONDIRENTRY *CURSORICON_FindBestIconRes( CURSORICONDIR * dir,
763 int width, int height, int colors )
765 int n;
767 n = CURSORICON_FindBestIcon( dir, CURSORICON_GetResIconEntry,
768 width, height, colors );
769 if ( n < 0 )
770 return NULL;
771 return &dir->idEntries[n];
774 static CURSORICONDIRENTRY *CURSORICON_FindBestCursorRes( CURSORICONDIR *dir,
775 int width, int height, int color )
777 int n = CURSORICON_FindBestCursor( dir, CURSORICON_GetResCursorEntry,
778 width, height, color );
779 if ( n < 0 )
780 return NULL;
781 return &dir->idEntries[n];
784 static BOOL CURSORICON_GetFileEntry( LPVOID dir, int n,
785 int *width, int *height, int *bits )
787 CURSORICONFILEDIR *filedir = dir;
788 CURSORICONFILEDIRENTRY *entry;
790 if ( filedir->idCount <= n )
791 return FALSE;
792 entry = &filedir->idEntries[n];
793 *width = entry->bWidth;
794 *height = entry->bHeight;
795 *bits = entry->bColorCount;
796 return TRUE;
799 static CURSORICONFILEDIRENTRY *CURSORICON_FindBestCursorFile( CURSORICONFILEDIR *dir,
800 int width, int height, int color )
802 int n = CURSORICON_FindBestCursor( dir, CURSORICON_GetFileEntry,
803 width, height, color );
804 if ( n < 0 )
805 return NULL;
806 return &dir->idEntries[n];
809 static CURSORICONFILEDIRENTRY *CURSORICON_FindBestIconFile( CURSORICONFILEDIR *dir,
810 int width, int height, int color )
812 int n = CURSORICON_FindBestIcon( dir, CURSORICON_GetFileEntry,
813 width, height, color );
814 if ( n < 0 )
815 return NULL;
816 return &dir->idEntries[n];
819 static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
820 POINT16 hotspot, BOOL bIcon,
821 DWORD dwVersion,
822 INT width, INT height,
823 UINT cFlag )
825 HGLOBAL16 hObj;
826 static HDC hdcMem;
827 int sizeAnd, sizeXor;
828 HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
829 BITMAP bmpXor, bmpAnd;
830 BOOL DoStretch;
831 INT size;
833 if (dwVersion == 0x00020000)
835 FIXME_(cursor)("\t2.xx resources are not supported\n");
836 return 0;
839 /* Check bitmap header */
841 if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
842 (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) ||
843 bmi->bmiHeader.biCompression != BI_RGB) )
845 WARN_(cursor)("\tinvalid resource bitmap header.\n");
846 return 0;
849 size = bitmap_info_size( bmi, DIB_RGB_COLORS );
851 if (!width) width = bmi->bmiHeader.biWidth;
852 if (!height) height = bmi->bmiHeader.biHeight/2;
853 DoStretch = (bmi->bmiHeader.biHeight/2 != height) ||
854 (bmi->bmiHeader.biWidth != width);
856 if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
857 if (screen_dc)
859 BITMAPINFO* pInfo;
861 /* Make sure we have room for the monochrome bitmap later on.
862 * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
863 * up to and including the biBitCount. In-memory icon resource
864 * format is as follows:
866 * BITMAPINFOHEADER icHeader // DIB header
867 * RGBQUAD icColors[] // Color table
868 * BYTE icXOR[] // DIB bits for XOR mask
869 * BYTE icAND[] // DIB bits for AND mask
872 if ((pInfo = HeapAlloc( GetProcessHeap(), 0,
873 max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))))
875 memcpy( pInfo, bmi, size );
876 pInfo->bmiHeader.biHeight /= 2;
878 /* Create the XOR bitmap */
880 if (DoStretch) {
881 if(bIcon)
883 hXorBits = CreateCompatibleBitmap(screen_dc, width, height);
885 else
887 hXorBits = CreateBitmap(width, height, 1, 1, NULL);
889 if(hXorBits)
891 HBITMAP hOld;
892 BOOL res = FALSE;
894 if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
895 if (hdcMem) {
896 hOld = SelectObject(hdcMem, hXorBits);
897 res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
898 bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2,
899 (char*)bmi + size, pInfo, DIB_RGB_COLORS, SRCCOPY);
900 SelectObject(hdcMem, hOld);
902 if (!res) { DeleteObject(hXorBits); hXorBits = 0; }
904 } else {
905 if (is_dib_monochrome(bmi)) {
906 hXorBits = CreateBitmap(width, height, 1, 1, NULL);
907 SetDIBits(screen_dc, hXorBits, 0, height,
908 (char*)bmi + size, pInfo, DIB_RGB_COLORS);
910 else
911 hXorBits = CreateDIBitmap(screen_dc, &pInfo->bmiHeader,
912 CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS);
915 if( hXorBits )
917 char* xbits = (char *)bmi + size +
918 get_dib_width_bytes( bmi->bmiHeader.biWidth,
919 bmi->bmiHeader.biBitCount ) * abs( bmi->bmiHeader.biHeight ) / 2;
921 pInfo->bmiHeader.biBitCount = 1;
922 if (pInfo->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
924 RGBQUAD *rgb = pInfo->bmiColors;
926 pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
927 rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
928 rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
929 rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
931 else
933 RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
935 rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
936 rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
939 /* Create the AND bitmap */
941 if (DoStretch) {
942 if ((hAndBits = CreateBitmap(width, height, 1, 1, NULL))) {
943 HBITMAP hOld;
944 BOOL res = FALSE;
946 if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
947 if (hdcMem) {
948 hOld = SelectObject(hdcMem, hAndBits);
949 res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
950 pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight,
951 xbits, pInfo, DIB_RGB_COLORS, SRCCOPY);
952 SelectObject(hdcMem, hOld);
954 if (!res) { DeleteObject(hAndBits); hAndBits = 0; }
956 } else {
957 hAndBits = CreateBitmap(width, height, 1, 1, NULL);
959 if (hAndBits) SetDIBits(screen_dc, hAndBits, 0, height,
960 xbits, pInfo, DIB_RGB_COLORS);
963 if( !hAndBits ) DeleteObject( hXorBits );
965 HeapFree( GetProcessHeap(), 0, pInfo );
969 if( !hXorBits || !hAndBits )
971 WARN_(cursor)("\tunable to create an icon bitmap.\n");
972 return 0;
975 /* Now create the CURSORICONINFO structure */
976 GetObjectA( hXorBits, sizeof(bmpXor), &bmpXor );
977 GetObjectA( hAndBits, sizeof(bmpAnd), &bmpAnd );
978 sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
979 sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
981 hObj = GlobalAlloc16( GMEM_MOVEABLE,
982 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
983 if (hObj)
985 CURSORICONINFO *info;
987 info = GlobalLock16( hObj );
988 info->ptHotSpot.x = hotspot.x;
989 info->ptHotSpot.y = hotspot.y;
990 info->nWidth = bmpXor.bmWidth;
991 info->nHeight = bmpXor.bmHeight;
992 info->nWidthBytes = bmpXor.bmWidthBytes;
993 info->bPlanes = bmpXor.bmPlanes;
994 info->bBitsPerPixel = bmpXor.bmBitsPixel;
996 /* Transfer the bitmap bits to the CURSORICONINFO structure */
998 GetBitmapBits( hAndBits, sizeAnd, (char *)(info + 1) );
999 GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
1000 GlobalUnlock16( hObj );
1003 DeleteObject( hAndBits );
1004 DeleteObject( hXorBits );
1006 return create_cursor( 1, 0, hObj );
1010 /**********************************************************************
1011 * .ANI cursor support
1013 #define RIFF_FOURCC( c0, c1, c2, c3 ) \
1014 ( (DWORD)(BYTE)(c0) | ( (DWORD)(BYTE)(c1) << 8 ) | \
1015 ( (DWORD)(BYTE)(c2) << 16 ) | ( (DWORD)(BYTE)(c3) << 24 ) )
1017 #define ANI_RIFF_ID RIFF_FOURCC('R', 'I', 'F', 'F')
1018 #define ANI_LIST_ID RIFF_FOURCC('L', 'I', 'S', 'T')
1019 #define ANI_ACON_ID RIFF_FOURCC('A', 'C', 'O', 'N')
1020 #define ANI_anih_ID RIFF_FOURCC('a', 'n', 'i', 'h')
1021 #define ANI_seq__ID RIFF_FOURCC('s', 'e', 'q', ' ')
1022 #define ANI_fram_ID RIFF_FOURCC('f', 'r', 'a', 'm')
1024 #define ANI_FLAG_ICON 0x1
1025 #define ANI_FLAG_SEQUENCE 0x2
1027 typedef struct {
1028 DWORD header_size;
1029 DWORD num_frames;
1030 DWORD num_steps;
1031 DWORD width;
1032 DWORD height;
1033 DWORD bpp;
1034 DWORD num_planes;
1035 DWORD display_rate;
1036 DWORD flags;
1037 } ani_header;
1039 typedef struct {
1040 DWORD data_size;
1041 const unsigned char *data;
1042 } riff_chunk_t;
1044 static void dump_ani_header( const ani_header *header )
1046 TRACE(" header size: %d\n", header->header_size);
1047 TRACE(" frames: %d\n", header->num_frames);
1048 TRACE(" steps: %d\n", header->num_steps);
1049 TRACE(" width: %d\n", header->width);
1050 TRACE(" height: %d\n", header->height);
1051 TRACE(" bpp: %d\n", header->bpp);
1052 TRACE(" planes: %d\n", header->num_planes);
1053 TRACE(" display rate: %d\n", header->display_rate);
1054 TRACE(" flags: 0x%08x\n", header->flags);
1059 * RIFF:
1060 * DWORD "RIFF"
1061 * DWORD size
1062 * DWORD riff_id
1063 * BYTE[] data
1065 * LIST:
1066 * DWORD "LIST"
1067 * DWORD size
1068 * DWORD list_id
1069 * BYTE[] data
1071 * CHUNK:
1072 * DWORD chunk_id
1073 * DWORD size
1074 * BYTE[] data
1076 static void riff_find_chunk( DWORD chunk_id, DWORD chunk_type, const riff_chunk_t *parent_chunk, riff_chunk_t *chunk )
1078 const unsigned char *ptr = parent_chunk->data;
1079 const unsigned char *end = parent_chunk->data + (parent_chunk->data_size - (2 * sizeof(DWORD)));
1081 if (chunk_type == ANI_LIST_ID || chunk_type == ANI_RIFF_ID) end -= sizeof(DWORD);
1083 while (ptr < end)
1085 if ((!chunk_type && *(DWORD *)ptr == chunk_id )
1086 || (chunk_type && *(DWORD *)ptr == chunk_type && *((DWORD *)ptr + 2) == chunk_id ))
1088 ptr += sizeof(DWORD);
1089 chunk->data_size = *(DWORD *)ptr;
1090 ptr += sizeof(DWORD);
1091 if (chunk_type == ANI_LIST_ID || chunk_type == ANI_RIFF_ID) ptr += sizeof(DWORD);
1092 chunk->data = ptr;
1094 return;
1097 ptr += sizeof(DWORD);
1098 ptr += *(DWORD *)ptr;
1099 ptr += sizeof(DWORD);
1105 * .ANI layout:
1107 * RIFF:'ACON' RIFF chunk
1108 * |- CHUNK:'anih' Header
1109 * |- CHUNK:'seq ' Sequence information (optional)
1110 * \- LIST:'fram' Frame list
1111 * |- CHUNK:icon Cursor frames
1112 * |- CHUNK:icon
1113 * |- ...
1114 * \- CHUNK:icon
1116 static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
1117 INT width, INT height )
1119 HCURSOR cursor;
1120 ani_header header = {0};
1121 LPBYTE frame_bits = 0;
1122 POINT16 hotspot;
1123 CURSORICONFILEDIRENTRY *entry;
1125 riff_chunk_t root_chunk = { bits_size, bits };
1126 riff_chunk_t ACON_chunk = {0};
1127 riff_chunk_t anih_chunk = {0};
1128 riff_chunk_t fram_chunk = {0};
1129 const unsigned char *icon_data;
1131 TRACE("bits %p, bits_size %d\n", bits, bits_size);
1133 if (!bits) return 0;
1135 riff_find_chunk( ANI_ACON_ID, ANI_RIFF_ID, &root_chunk, &ACON_chunk );
1136 if (!ACON_chunk.data)
1138 ERR("Failed to get root chunk.\n");
1139 return 0;
1142 riff_find_chunk( ANI_anih_ID, 0, &ACON_chunk, &anih_chunk );
1143 if (!anih_chunk.data)
1145 ERR("Failed to get 'anih' chunk.\n");
1146 return 0;
1148 memcpy( &header, anih_chunk.data, sizeof(header) );
1149 dump_ani_header( &header );
1151 riff_find_chunk( ANI_fram_ID, ANI_LIST_ID, &ACON_chunk, &fram_chunk );
1152 if (!fram_chunk.data)
1154 ERR("Failed to get icon list.\n");
1155 return 0;
1158 /* FIXME: For now, just load the first frame. Before we can load all the
1159 * frames, we need to write the needed code in wineserver, etc. to handle
1160 * cursors. Once this code is written, we can extend it to support .ani
1161 * cursors and then update user32 and winex11.drv to load all frames.
1163 * Hopefully this will at least make some games (C&C3, etc.) more playable
1164 * in the mean time.
1166 FIXME("Loading all frames for .ani cursors not implemented.\n");
1167 icon_data = fram_chunk.data + (2 * sizeof(DWORD));
1169 entry = CURSORICON_FindBestCursorFile( (CURSORICONFILEDIR *) icon_data,
1170 width, height, 1 );
1172 frame_bits = HeapAlloc( GetProcessHeap(), 0, entry->dwDIBSize );
1173 memcpy( frame_bits, icon_data + entry->dwDIBOffset, entry->dwDIBSize );
1175 if (!header.width || !header.height)
1177 header.width = entry->bWidth;
1178 header.height = entry->bHeight;
1181 hotspot.x = entry->xHotspot;
1182 hotspot.y = entry->yHotspot;
1184 cursor = CURSORICON_CreateIconFromBMI( (BITMAPINFO *) frame_bits, hotspot,
1185 FALSE, 0x00030000, header.width, header.height, 0 );
1187 HeapFree( GetProcessHeap(), 0, frame_bits );
1189 return cursor;
1193 /**********************************************************************
1194 * CreateIconFromResourceEx (USER32.@)
1196 * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
1197 * with cbSize parameter as well.
1199 HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
1200 BOOL bIcon, DWORD dwVersion,
1201 INT width, INT height,
1202 UINT cFlag )
1204 POINT16 hotspot;
1205 BITMAPINFO *bmi;
1207 hotspot.x = ICON_HOTSPOT;
1208 hotspot.y = ICON_HOTSPOT;
1210 TRACE_(cursor)("%p (%u bytes), ver %08x, %ix%i %s %s\n",
1211 bits, cbSize, dwVersion, width, height,
1212 bIcon ? "icon" : "cursor", (cFlag & LR_MONOCHROME) ? "mono" : "" );
1214 if (bIcon)
1215 bmi = (BITMAPINFO *)bits;
1216 else /* get the hotspot */
1218 POINT16 *pt = (POINT16 *)bits;
1219 hotspot = *pt;
1220 bmi = (BITMAPINFO *)(pt + 1);
1223 return CURSORICON_CreateIconFromBMI( bmi, hotspot, bIcon, dwVersion,
1224 width, height, cFlag );
1228 /**********************************************************************
1229 * CreateIconFromResource (USER32.@)
1231 HICON WINAPI CreateIconFromResource( LPBYTE bits, UINT cbSize,
1232 BOOL bIcon, DWORD dwVersion)
1234 return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
1238 static HICON CURSORICON_LoadFromFile( LPCWSTR filename,
1239 INT width, INT height, INT colors,
1240 BOOL fCursor, UINT loadflags)
1242 CURSORICONFILEDIRENTRY *entry;
1243 CURSORICONFILEDIR *dir;
1244 DWORD filesize = 0;
1245 HICON hIcon = 0;
1246 LPBYTE bits;
1247 POINT16 hotspot;
1249 TRACE("loading %s\n", debugstr_w( filename ));
1251 bits = map_fileW( filename, &filesize );
1252 if (!bits)
1253 return hIcon;
1255 /* Check for .ani. */
1256 if (memcmp( bits, "RIFF", 4 ) == 0)
1258 hIcon = CURSORICON_CreateIconFromANI( bits, filesize, width, height );
1259 goto end;
1262 dir = (CURSORICONFILEDIR*) bits;
1263 if ( filesize < sizeof(*dir) )
1264 goto end;
1266 if ( filesize < (sizeof(*dir) + sizeof(dir->idEntries[0])*(dir->idCount-1)) )
1267 goto end;
1269 if ( fCursor )
1270 entry = CURSORICON_FindBestCursorFile( dir, width, height, colors );
1271 else
1272 entry = CURSORICON_FindBestIconFile( dir, width, height, colors );
1274 if ( !entry )
1275 goto end;
1277 /* check that we don't run off the end of the file */
1278 if ( entry->dwDIBOffset > filesize )
1279 goto end;
1280 if ( entry->dwDIBOffset + entry->dwDIBSize > filesize )
1281 goto end;
1283 hotspot.x = entry->xHotspot;
1284 hotspot.y = entry->yHotspot;
1285 hIcon = CURSORICON_CreateIconFromBMI( (BITMAPINFO *)&bits[entry->dwDIBOffset],
1286 hotspot, !fCursor, 0x00030000,
1287 width, height, loadflags );
1288 end:
1289 TRACE("loaded %s -> %p\n", debugstr_w( filename ), hIcon );
1290 UnmapViewOfFile( bits );
1291 return hIcon;
1294 /**********************************************************************
1295 * CURSORICON_Load
1297 * Load a cursor or icon from resource or file.
1299 static HICON CURSORICON_Load(HINSTANCE hInstance, LPCWSTR name,
1300 INT width, INT height, INT colors,
1301 BOOL fCursor, UINT loadflags)
1303 HANDLE handle = 0;
1304 HICON hIcon = 0;
1305 HRSRC hRsrc, hGroupRsrc;
1306 CURSORICONDIR *dir;
1307 CURSORICONDIRENTRY *dirEntry;
1308 LPBYTE bits;
1309 WORD wResId;
1310 DWORD dwBytesInRes;
1312 TRACE("%p, %s, %dx%d, colors %d, fCursor %d, flags 0x%04x\n",
1313 hInstance, debugstr_w(name), width, height, colors, fCursor, loadflags);
1315 if ( loadflags & LR_LOADFROMFILE ) /* Load from file */
1316 return CURSORICON_LoadFromFile( name, width, height, colors, fCursor, loadflags );
1318 if (!hInstance) hInstance = user32_module; /* Load OEM cursor/icon */
1320 /* Normalize hInstance (must be uniquely represented for icon cache) */
1322 if (!HIWORD( hInstance ))
1323 hInstance = HINSTANCE_32(GetExePtr( HINSTANCE_16(hInstance) ));
1325 /* Get directory resource ID */
1327 if (!(hRsrc = FindResourceW( hInstance, name,
1328 (LPWSTR)(fCursor ? RT_GROUP_CURSOR : RT_GROUP_ICON) )))
1329 return 0;
1330 hGroupRsrc = hRsrc;
1332 /* Find the best entry in the directory */
1334 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
1335 if (!(dir = LockResource( handle ))) return 0;
1336 if (fCursor)
1337 dirEntry = CURSORICON_FindBestCursorRes( dir, width, height, 1);
1338 else
1339 dirEntry = CURSORICON_FindBestIconRes( dir, width, height, colors );
1340 if (!dirEntry) return 0;
1341 wResId = dirEntry->wResId;
1342 dwBytesInRes = dirEntry->dwBytesInRes;
1343 FreeResource( handle );
1345 /* Load the resource */
1347 if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
1348 (LPWSTR)(fCursor ? RT_CURSOR : RT_ICON) ))) return 0;
1350 /* If shared icon, check whether it was already loaded */
1351 if ( (loadflags & LR_SHARED)
1352 && (hIcon = CURSORICON_FindSharedIcon( hInstance, hRsrc ) ) != 0 )
1353 return hIcon;
1355 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
1356 bits = LockResource( handle );
1357 hIcon = CreateIconFromResourceEx( bits, dwBytesInRes,
1358 !fCursor, 0x00030000, width, height, loadflags);
1359 FreeResource( handle );
1361 /* If shared icon, add to icon cache */
1363 if ( hIcon && (loadflags & LR_SHARED) )
1364 CURSORICON_AddSharedIcon( hInstance, hRsrc, hGroupRsrc, hIcon );
1366 return hIcon;
1369 /***********************************************************************
1370 * CURSORICON_Copy
1372 * Make a copy of a cursor or icon.
1374 static HICON CURSORICON_Copy( HINSTANCE16 hInst16, HICON hIcon )
1376 char *ptrOld, *ptrNew;
1377 int size;
1378 HICON16 hOld = HICON_16(hIcon);
1379 HICON16 hNew;
1381 if (!(ptrOld = GlobalLock16( hOld ))) return 0;
1382 if (hInst16 && !(hInst16 = GetExePtr( hInst16 ))) return 0;
1383 size = GlobalSize16( hOld );
1384 hNew = GlobalAlloc16( GMEM_MOVEABLE, size );
1385 FarSetOwner16( hNew, hInst16 );
1386 ptrNew = GlobalLock16( hNew );
1387 memcpy( ptrNew, ptrOld, size );
1388 GlobalUnlock16( hOld );
1389 GlobalUnlock16( hNew );
1391 return create_cursor( 1, 0, hNew );
1394 /*************************************************************************
1395 * CURSORICON_ExtCopy
1397 * Copies an Image from the Cache if LR_COPYFROMRESOURCE is specified
1399 * PARAMS
1400 * Handle [I] handle to an Image
1401 * nType [I] Type of Handle (IMAGE_CURSOR | IMAGE_ICON)
1402 * iDesiredCX [I] The Desired width of the Image
1403 * iDesiredCY [I] The desired height of the Image
1404 * nFlags [I] The flags from CopyImage
1406 * RETURNS
1407 * Success: The new handle of the Image
1409 * NOTES
1410 * LR_COPYDELETEORG and LR_MONOCHROME are currently not implemented.
1411 * LR_MONOCHROME should be implemented by CreateIconFromResourceEx.
1412 * LR_COPYFROMRESOURCE will only work if the Image is in the Cache.
1417 static HICON CURSORICON_ExtCopy(HICON hIcon, UINT nType,
1418 INT iDesiredCX, INT iDesiredCY,
1419 UINT nFlags)
1421 HICON hNew=0;
1423 TRACE_(icon)("hIcon %p, nType %u, iDesiredCX %i, iDesiredCY %i, nFlags %u\n",
1424 hIcon, nType, iDesiredCX, iDesiredCY, nFlags);
1426 if(hIcon == 0)
1428 return 0;
1431 /* Best Fit or Monochrome */
1432 if( (nFlags & LR_COPYFROMRESOURCE
1433 && (iDesiredCX > 0 || iDesiredCY > 0))
1434 || nFlags & LR_MONOCHROME)
1436 ICONCACHE* pIconCache = CURSORICON_FindCache(hIcon);
1438 /* Not Found in Cache, then do a straight copy
1440 if(pIconCache == NULL)
1442 hNew = CURSORICON_Copy(0, hIcon);
1443 if(nFlags & LR_COPYFROMRESOURCE)
1445 TRACE_(icon)("LR_COPYFROMRESOURCE: Failed to load from cache\n");
1448 else
1450 int iTargetCY = iDesiredCY, iTargetCX = iDesiredCX;
1451 LPBYTE pBits;
1452 HANDLE hMem;
1453 HRSRC hRsrc;
1454 DWORD dwBytesInRes;
1455 WORD wResId;
1456 CURSORICONDIR *pDir;
1457 CURSORICONDIRENTRY *pDirEntry;
1458 BOOL bIsIcon = (nType == IMAGE_ICON);
1460 /* Completing iDesiredCX CY for Monochrome Bitmaps if needed
1462 if(((nFlags & LR_MONOCHROME) && !(nFlags & LR_COPYFROMRESOURCE))
1463 || (iDesiredCX == 0 && iDesiredCY == 0))
1465 iDesiredCY = GetSystemMetrics(bIsIcon ?
1466 SM_CYICON : SM_CYCURSOR);
1467 iDesiredCX = GetSystemMetrics(bIsIcon ?
1468 SM_CXICON : SM_CXCURSOR);
1471 /* Retrieve the CURSORICONDIRENTRY
1473 if (!(hMem = LoadResource( pIconCache->hModule ,
1474 pIconCache->hGroupRsrc)))
1476 return 0;
1478 if (!(pDir = LockResource( hMem )))
1480 return 0;
1483 /* Find Best Fit
1485 if(bIsIcon)
1487 pDirEntry = CURSORICON_FindBestIconRes(
1488 pDir, iDesiredCX, iDesiredCY, 256 );
1490 else
1492 pDirEntry = CURSORICON_FindBestCursorRes(
1493 pDir, iDesiredCX, iDesiredCY, 1);
1496 wResId = pDirEntry->wResId;
1497 dwBytesInRes = pDirEntry->dwBytesInRes;
1498 FreeResource(hMem);
1500 TRACE_(icon)("ResID %u, BytesInRes %u, Width %d, Height %d DX %d, DY %d\n",
1501 wResId, dwBytesInRes, pDirEntry->ResInfo.icon.bWidth,
1502 pDirEntry->ResInfo.icon.bHeight, iDesiredCX, iDesiredCY);
1504 /* Get the Best Fit
1506 if (!(hRsrc = FindResourceW(pIconCache->hModule ,
1507 MAKEINTRESOURCEW(wResId), (LPWSTR)(bIsIcon ? RT_ICON : RT_CURSOR))))
1509 return 0;
1511 if (!(hMem = LoadResource( pIconCache->hModule , hRsrc )))
1513 return 0;
1516 pBits = LockResource( hMem );
1518 if(nFlags & LR_DEFAULTSIZE)
1520 iTargetCY = GetSystemMetrics(SM_CYICON);
1521 iTargetCX = GetSystemMetrics(SM_CXICON);
1524 /* Create a New Icon with the proper dimension
1526 hNew = CreateIconFromResourceEx( pBits, dwBytesInRes,
1527 bIsIcon, 0x00030000, iTargetCX, iTargetCY, nFlags);
1528 FreeResource(hMem);
1531 else hNew = CURSORICON_Copy(0, hIcon);
1532 return hNew;
1536 /***********************************************************************
1537 * CreateCursor (USER32.@)
1539 HCURSOR WINAPI CreateCursor( HINSTANCE hInstance,
1540 INT xHotSpot, INT yHotSpot,
1541 INT nWidth, INT nHeight,
1542 LPCVOID lpANDbits, LPCVOID lpXORbits )
1544 CURSORICONINFO info;
1546 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1547 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1549 info.ptHotSpot.x = xHotSpot;
1550 info.ptHotSpot.y = yHotSpot;
1551 info.nWidth = nWidth;
1552 info.nHeight = nHeight;
1553 info.nWidthBytes = 0;
1554 info.bPlanes = 1;
1555 info.bBitsPerPixel = 1;
1557 return HICON_32(CreateCursorIconIndirect16(0, &info, lpANDbits, lpXORbits));
1561 /***********************************************************************
1562 * CreateIcon (USER.407)
1564 HICON16 WINAPI CreateIcon16( HINSTANCE16 hInstance, INT16 nWidth,
1565 INT16 nHeight, BYTE bPlanes, BYTE bBitsPixel,
1566 LPCVOID lpANDbits, LPCVOID lpXORbits )
1568 CURSORICONINFO info;
1570 TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1571 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1573 info.ptHotSpot.x = ICON_HOTSPOT;
1574 info.ptHotSpot.y = ICON_HOTSPOT;
1575 info.nWidth = nWidth;
1576 info.nHeight = nHeight;
1577 info.nWidthBytes = 0;
1578 info.bPlanes = bPlanes;
1579 info.bBitsPerPixel = bBitsPixel;
1581 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1585 /***********************************************************************
1586 * CreateIcon (USER32.@)
1588 * Creates an icon based on the specified bitmaps. The bitmaps must be
1589 * provided in a device dependent format and will be resized to
1590 * (SM_CXICON,SM_CYICON) and depth converted to match the screen's color
1591 * depth. The provided bitmaps must be top-down bitmaps.
1592 * Although Windows does not support 15bpp(*) this API must support it
1593 * for Winelib applications.
1595 * (*) Windows does not support 15bpp but it supports the 555 RGB 16bpp
1596 * format!
1598 * RETURNS
1599 * Success: handle to an icon
1600 * Failure: NULL
1602 * FIXME: Do we need to resize the bitmaps?
1604 HICON WINAPI CreateIcon(
1605 HINSTANCE hInstance, /* [in] the application's hInstance */
1606 INT nWidth, /* [in] the width of the provided bitmaps */
1607 INT nHeight, /* [in] the height of the provided bitmaps */
1608 BYTE bPlanes, /* [in] the number of planes in the provided bitmaps */
1609 BYTE bBitsPixel, /* [in] the number of bits per pixel of the lpXORbits bitmap */
1610 LPCVOID lpANDbits, /* [in] a monochrome bitmap representing the icon's mask */
1611 LPCVOID lpXORbits) /* [in] the icon's 'color' bitmap */
1613 ICONINFO iinfo;
1614 HICON hIcon;
1616 TRACE_(icon)("%dx%d, planes %d, bpp %d, xor %p, and %p\n",
1617 nWidth, nHeight, bPlanes, bBitsPixel, lpXORbits, lpANDbits);
1619 iinfo.fIcon = TRUE;
1620 iinfo.xHotspot = ICON_HOTSPOT;
1621 iinfo.yHotspot = ICON_HOTSPOT;
1622 iinfo.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpANDbits );
1623 iinfo.hbmColor = CreateBitmap( nWidth, nHeight, bPlanes, bBitsPixel, lpXORbits );
1625 hIcon = CreateIconIndirect( &iinfo );
1627 DeleteObject( iinfo.hbmMask );
1628 DeleteObject( iinfo.hbmColor );
1630 return hIcon;
1634 /***********************************************************************
1635 * CreateCursorIconIndirect (USER.408)
1637 HGLOBAL16 WINAPI CreateCursorIconIndirect16( HINSTANCE16 hInstance,
1638 CURSORICONINFO *info,
1639 LPCVOID lpANDbits,
1640 LPCVOID lpXORbits )
1642 HGLOBAL16 handle;
1643 char *ptr;
1644 int sizeAnd, sizeXor;
1646 hInstance = GetExePtr( hInstance ); /* Make it a module handle */
1647 if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
1648 info->nWidthBytes = get_bitmap_width_bytes(info->nWidth,info->bBitsPerPixel);
1649 sizeXor = info->nHeight * info->nWidthBytes;
1650 sizeAnd = info->nHeight * get_bitmap_width_bytes( info->nWidth, 1 );
1651 if (!(handle = GlobalAlloc16( GMEM_MOVEABLE,
1652 sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
1653 return 0;
1654 FarSetOwner16( handle, hInstance );
1655 ptr = GlobalLock16( handle );
1656 memcpy( ptr, info, sizeof(*info) );
1657 memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
1658 memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
1659 GlobalUnlock16( handle );
1660 return HICON_16(create_cursor( 1, 0, handle ));
1664 /***********************************************************************
1665 * CopyIcon (USER.368)
1667 HICON16 WINAPI CopyIcon16( HINSTANCE16 hInstance, HICON16 hIcon )
1669 TRACE_(icon)("%04x %04x\n", hInstance, hIcon );
1670 return HICON_16(CURSORICON_Copy(hInstance, HICON_32(hIcon)));
1674 /***********************************************************************
1675 * CopyIcon (USER32.@)
1677 HICON WINAPI CopyIcon( HICON hIcon )
1679 TRACE_(icon)("%p\n", hIcon );
1680 return CURSORICON_Copy( 0, hIcon );
1684 /***********************************************************************
1685 * CopyCursor (USER.369)
1687 HCURSOR16 WINAPI CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
1689 TRACE_(cursor)("%04x %04x\n", hInstance, hCursor );
1690 return HICON_16(CURSORICON_Copy(hInstance, HCURSOR_32(hCursor)));
1693 /**********************************************************************
1694 * DestroyIcon32 (USER.610)
1696 * This routine is actually exported from Win95 USER under the name
1697 * DestroyIcon32 ... The behaviour implemented here should mimic
1698 * the Win95 one exactly, especially the return values, which
1699 * depend on the setting of various flags.
1701 WORD WINAPI DestroyIcon32( HGLOBAL16 handle, UINT16 flags )
1703 WORD retv;
1705 TRACE_(icon)("(%04x, %04x)\n", handle, flags );
1707 /* Check whether destroying active cursor */
1709 if ( get_user_thread_info()->cursor == HICON_32(handle) )
1711 WARN_(cursor)("Destroying active cursor!\n" );
1712 return FALSE;
1715 /* Try shared cursor/icon first */
1717 if ( !(flags & CID_NONSHARED) )
1719 INT count = CURSORICON_DelSharedIcon(HICON_32(handle));
1721 if ( count != -1 )
1722 return (flags & CID_WIN32)? TRUE : (count == 0);
1724 /* FIXME: OEM cursors/icons should be recognized */
1727 /* Now assume non-shared cursor/icon */
1729 retv = destroy_cursor( HCURSOR_32(handle) );
1730 return (flags & CID_RESOURCE)? retv : TRUE;
1733 /***********************************************************************
1734 * DestroyIcon (USER32.@)
1736 BOOL WINAPI DestroyIcon( HICON hIcon )
1738 return DestroyIcon32(HICON_16(hIcon), CID_WIN32);
1742 /***********************************************************************
1743 * DestroyCursor (USER32.@)
1745 BOOL WINAPI DestroyCursor( HCURSOR hCursor )
1747 return DestroyIcon32(HCURSOR_16(hCursor), CID_WIN32);
1751 /***********************************************************************
1752 * DrawIcon (USER32.@)
1754 BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
1756 CURSORICONINFO *ptr;
1757 HDC hMemDC;
1758 HBITMAP hXorBits, hAndBits;
1759 COLORREF oldFg, oldBg;
1761 TRACE("%p, (%d,%d), %p\n", hdc, x, y, hIcon);
1763 if (!(ptr = GlobalLock16(HICON_16(hIcon)))) return FALSE;
1764 if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
1765 hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1,
1766 (char *)(ptr+1) );
1767 hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
1768 ptr->bBitsPerPixel, (char *)(ptr + 1)
1769 + ptr->nHeight * get_bitmap_width_bytes(ptr->nWidth,1) );
1770 oldFg = SetTextColor( hdc, RGB(0,0,0) );
1771 oldBg = SetBkColor( hdc, RGB(255,255,255) );
1773 if (hXorBits && hAndBits)
1775 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1776 BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
1777 SelectObject( hMemDC, hXorBits );
1778 BitBlt(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
1779 SelectObject( hMemDC, hBitTemp );
1781 DeleteDC( hMemDC );
1782 if (hXorBits) DeleteObject( hXorBits );
1783 if (hAndBits) DeleteObject( hAndBits );
1784 GlobalUnlock16(HICON_16(hIcon));
1785 SetTextColor( hdc, oldFg );
1786 SetBkColor( hdc, oldBg );
1787 return TRUE;
1790 /***********************************************************************
1791 * DumpIcon (USER.459)
1793 DWORD WINAPI DumpIcon16( SEGPTR pInfo, WORD *lpLen,
1794 SEGPTR *lpXorBits, SEGPTR *lpAndBits )
1796 CURSORICONINFO *info = MapSL( pInfo );
1797 int sizeAnd, sizeXor;
1799 if (!info) return 0;
1800 sizeXor = info->nHeight * info->nWidthBytes;
1801 sizeAnd = info->nHeight * get_bitmap_width_bytes( info->nWidth, 1 );
1802 if (lpAndBits) *lpAndBits = pInfo + sizeof(CURSORICONINFO);
1803 if (lpXorBits) *lpXorBits = pInfo + sizeof(CURSORICONINFO) + sizeAnd;
1804 if (lpLen) *lpLen = sizeof(CURSORICONINFO) + sizeAnd + sizeXor;
1805 return MAKELONG( sizeXor, sizeXor );
1809 /***********************************************************************
1810 * SetCursor (USER32.@)
1812 * Set the cursor shape.
1814 * RETURNS
1815 * A handle to the previous cursor shape.
1817 HCURSOR WINAPI SetCursor( HCURSOR hCursor /* [in] Handle of cursor to show */ )
1819 struct user_thread_info *thread_info = get_user_thread_info();
1820 HCURSOR hOldCursor;
1822 if (hCursor == thread_info->cursor) return hCursor; /* No change */
1823 TRACE("%p\n", hCursor);
1824 hOldCursor = thread_info->cursor;
1825 thread_info->cursor = hCursor;
1826 /* Change the cursor shape only if it is visible */
1827 if (thread_info->cursor_count >= 0)
1829 USER_Driver->pSetCursor( (CURSORICONINFO*)GlobalLock16(HCURSOR_16(hCursor)) );
1830 GlobalUnlock16(HCURSOR_16(hCursor));
1832 return hOldCursor;
1835 /***********************************************************************
1836 * ShowCursor (USER32.@)
1838 INT WINAPI ShowCursor( BOOL bShow )
1840 struct user_thread_info *thread_info = get_user_thread_info();
1842 TRACE("%d, count=%d\n", bShow, thread_info->cursor_count );
1844 if (bShow)
1846 if (++thread_info->cursor_count == 0) /* Show it */
1848 USER_Driver->pSetCursor((CURSORICONINFO*)GlobalLock16(HCURSOR_16(thread_info->cursor)));
1849 GlobalUnlock16(HCURSOR_16(thread_info->cursor));
1852 else
1854 if (--thread_info->cursor_count == -1) /* Hide it */
1855 USER_Driver->pSetCursor( NULL );
1857 return thread_info->cursor_count;
1860 /***********************************************************************
1861 * GetCursor (USER32.@)
1863 HCURSOR WINAPI GetCursor(void)
1865 return get_user_thread_info()->cursor;
1869 /***********************************************************************
1870 * ClipCursor (USER32.@)
1872 BOOL WINAPI ClipCursor( const RECT *rect )
1874 RECT virt;
1876 SetRect( &virt, 0, 0, GetSystemMetrics( SM_CXVIRTUALSCREEN ),
1877 GetSystemMetrics( SM_CYVIRTUALSCREEN ) );
1878 OffsetRect( &virt, GetSystemMetrics( SM_XVIRTUALSCREEN ),
1879 GetSystemMetrics( SM_YVIRTUALSCREEN ) );
1881 TRACE( "Clipping to: %s was: %s screen: %s\n", wine_dbgstr_rect(rect),
1882 wine_dbgstr_rect(&CURSOR_ClipRect), wine_dbgstr_rect(&virt) );
1884 if (!IntersectRect( &CURSOR_ClipRect, &virt, rect ))
1885 CURSOR_ClipRect = virt;
1887 USER_Driver->pClipCursor( rect );
1888 return TRUE;
1892 /***********************************************************************
1893 * GetClipCursor (USER32.@)
1895 BOOL WINAPI GetClipCursor( RECT *rect )
1897 /* If this is first time - initialize the rect */
1898 if (IsRectEmpty( &CURSOR_ClipRect )) ClipCursor( NULL );
1900 return CopyRect( rect, &CURSOR_ClipRect );
1904 /***********************************************************************
1905 * SetSystemCursor (USER32.@)
1907 BOOL WINAPI SetSystemCursor(HCURSOR hcur, DWORD id)
1909 FIXME("(%p,%08x),stub!\n", hcur, id);
1910 return TRUE;
1914 /**********************************************************************
1915 * LookupIconIdFromDirectoryEx (USER.364)
1917 * FIXME: exact parameter sizes
1919 INT16 WINAPI LookupIconIdFromDirectoryEx16( LPBYTE dir, BOOL16 bIcon,
1920 INT16 width, INT16 height, UINT16 cFlag )
1922 return LookupIconIdFromDirectoryEx( dir, bIcon, width, height, cFlag );
1925 /**********************************************************************
1926 * LookupIconIdFromDirectoryEx (USER32.@)
1928 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE xdir, BOOL bIcon,
1929 INT width, INT height, UINT cFlag )
1931 CURSORICONDIR *dir = (CURSORICONDIR*)xdir;
1932 UINT retVal = 0;
1933 if( dir && !dir->idReserved && (dir->idType & 3) )
1935 CURSORICONDIRENTRY* entry;
1936 HDC hdc;
1937 UINT palEnts;
1938 int colors;
1939 hdc = GetDC(0);
1940 palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
1941 if (palEnts == 0)
1942 palEnts = 256;
1943 colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
1945 ReleaseDC(0, hdc);
1947 if( bIcon )
1948 entry = CURSORICON_FindBestIconRes( dir, width, height, colors );
1949 else
1950 entry = CURSORICON_FindBestCursorRes( dir, width, height, 1);
1952 if( entry ) retVal = entry->wResId;
1954 else WARN_(cursor)("invalid resource directory\n");
1955 return retVal;
1958 /**********************************************************************
1959 * LookupIconIdFromDirectory (USER.?)
1961 INT16 WINAPI LookupIconIdFromDirectory16( LPBYTE dir, BOOL16 bIcon )
1963 return LookupIconIdFromDirectoryEx16( dir, bIcon,
1964 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1965 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1968 /**********************************************************************
1969 * LookupIconIdFromDirectory (USER32.@)
1971 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1973 return LookupIconIdFromDirectoryEx( dir, bIcon,
1974 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1975 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1978 /**********************************************************************
1979 * GetIconID (USER.455)
1981 WORD WINAPI GetIconID16( HGLOBAL16 hResource, DWORD resType )
1983 LPBYTE lpDir = GlobalLock16(hResource);
1985 TRACE_(cursor)("hRes=%04x, entries=%i\n",
1986 hResource, lpDir ? ((CURSORICONDIR*)lpDir)->idCount : 0);
1988 switch(resType)
1990 case RT_CURSOR:
1991 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, FALSE,
1992 GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1993 case RT_ICON:
1994 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, TRUE,
1995 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0 );
1996 default:
1997 WARN_(cursor)("invalid res type %d\n", resType );
1999 return 0;
2002 /**********************************************************************
2003 * LoadCursorIconHandler (USER.336)
2005 * Supposed to load resources of Windows 2.x applications.
2007 HGLOBAL16 WINAPI LoadCursorIconHandler16( HGLOBAL16 hResource, HMODULE16 hModule, HRSRC16 hRsrc )
2009 FIXME_(cursor)("(%04x,%04x,%04x): old 2.x resources are not supported!\n",
2010 hResource, hModule, hRsrc);
2011 return 0;
2014 /**********************************************************************
2015 * LoadIconHandler (USER.456)
2017 HICON16 WINAPI LoadIconHandler16( HGLOBAL16 hResource, BOOL16 bNew )
2019 LPBYTE bits = LockResource16( hResource );
2021 TRACE_(cursor)("hRes=%04x\n",hResource);
2023 return HICON_16(CreateIconFromResourceEx( bits, 0, TRUE,
2024 bNew ? 0x00030000 : 0x00020000, 0, 0, LR_DEFAULTCOLOR));
2027 /***********************************************************************
2028 * LoadCursorW (USER32.@)
2030 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
2032 TRACE("%p, %s\n", hInstance, debugstr_w(name));
2034 return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0,
2035 LR_SHARED | LR_DEFAULTSIZE );
2038 /***********************************************************************
2039 * LoadCursorA (USER32.@)
2041 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
2043 TRACE("%p, %s\n", hInstance, debugstr_a(name));
2045 return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0,
2046 LR_SHARED | LR_DEFAULTSIZE );
2049 /***********************************************************************
2050 * LoadCursorFromFileW (USER32.@)
2052 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
2054 TRACE("%s\n", debugstr_w(name));
2056 return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0,
2057 LR_LOADFROMFILE | LR_DEFAULTSIZE );
2060 /***********************************************************************
2061 * LoadCursorFromFileA (USER32.@)
2063 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
2065 TRACE("%s\n", debugstr_a(name));
2067 return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0,
2068 LR_LOADFROMFILE | LR_DEFAULTSIZE );
2071 /***********************************************************************
2072 * LoadIconW (USER32.@)
2074 HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
2076 TRACE("%p, %s\n", hInstance, debugstr_w(name));
2078 return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0,
2079 LR_SHARED | LR_DEFAULTSIZE );
2082 /***********************************************************************
2083 * LoadIconA (USER32.@)
2085 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
2087 TRACE("%p, %s\n", hInstance, debugstr_a(name));
2089 return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0,
2090 LR_SHARED | LR_DEFAULTSIZE );
2093 /**********************************************************************
2094 * GetIconInfo (USER32.@)
2096 BOOL WINAPI GetIconInfo(HICON hIcon, PICONINFO iconinfo)
2098 CURSORICONINFO *ciconinfo;
2099 INT height;
2101 ciconinfo = GlobalLock16(HICON_16(hIcon));
2102 if (!ciconinfo)
2103 return FALSE;
2105 TRACE("%p => %dx%d, %d bpp\n", hIcon,
2106 ciconinfo->nWidth, ciconinfo->nHeight, ciconinfo->bBitsPerPixel);
2108 if ( (ciconinfo->ptHotSpot.x == ICON_HOTSPOT) &&
2109 (ciconinfo->ptHotSpot.y == ICON_HOTSPOT) )
2111 iconinfo->fIcon = TRUE;
2112 iconinfo->xHotspot = ciconinfo->nWidth / 2;
2113 iconinfo->yHotspot = ciconinfo->nHeight / 2;
2115 else
2117 iconinfo->fIcon = FALSE;
2118 iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
2119 iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
2122 height = ciconinfo->nHeight;
2124 if (ciconinfo->bBitsPerPixel > 1)
2126 iconinfo->hbmColor = CreateBitmap( ciconinfo->nWidth, ciconinfo->nHeight,
2127 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
2128 (char *)(ciconinfo + 1)
2129 + ciconinfo->nHeight *
2130 get_bitmap_width_bytes (ciconinfo->nWidth,1) );
2132 else
2134 iconinfo->hbmColor = 0;
2135 height *= 2;
2138 iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, height,
2139 1, 1, (char *)(ciconinfo + 1));
2141 GlobalUnlock16(HICON_16(hIcon));
2143 return TRUE;
2146 /**********************************************************************
2147 * CreateIconIndirect (USER32.@)
2149 HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
2151 DIBSECTION bmpXor;
2152 BITMAP bmpAnd;
2153 HICON16 hObj;
2154 int xor_objsize = 0, sizeXor = 0, sizeAnd, planes, bpp;
2156 TRACE("color %p, mask %p, hotspot %ux%u, fIcon %d\n",
2157 iconinfo->hbmColor, iconinfo->hbmMask,
2158 iconinfo->xHotspot, iconinfo->yHotspot, iconinfo->fIcon);
2160 if (!iconinfo->hbmMask) return 0;
2162 planes = GetDeviceCaps( screen_dc, PLANES );
2163 bpp = GetDeviceCaps( screen_dc, BITSPIXEL );
2165 if (iconinfo->hbmColor)
2167 xor_objsize = GetObjectW( iconinfo->hbmColor, sizeof(bmpXor), &bmpXor );
2168 TRACE("color: width %d, height %d, width bytes %d, planes %u, bpp %u\n",
2169 bmpXor.dsBm.bmWidth, bmpXor.dsBm.bmHeight, bmpXor.dsBm.bmWidthBytes,
2170 bmpXor.dsBm.bmPlanes, bmpXor.dsBm.bmBitsPixel);
2171 /* we can use either depth 1 or screen depth for xor bitmap */
2172 if (bmpXor.dsBm.bmPlanes == 1 && bmpXor.dsBm.bmBitsPixel == 1) planes = bpp = 1;
2173 sizeXor = bmpXor.dsBm.bmHeight * planes * get_bitmap_width_bytes( bmpXor.dsBm.bmWidth, bpp );
2175 GetObjectW( iconinfo->hbmMask, sizeof(bmpAnd), &bmpAnd );
2176 TRACE("mask: width %d, height %d, width bytes %d, planes %u, bpp %u\n",
2177 bmpAnd.bmWidth, bmpAnd.bmHeight, bmpAnd.bmWidthBytes,
2178 bmpAnd.bmPlanes, bmpAnd.bmBitsPixel);
2180 sizeAnd = bmpAnd.bmHeight * get_bitmap_width_bytes(bmpAnd.bmWidth, 1);
2182 hObj = GlobalAlloc16( GMEM_MOVEABLE,
2183 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
2184 if (hObj)
2186 CURSORICONINFO *info;
2188 info = GlobalLock16( hObj );
2190 /* If we are creating an icon, the hotspot is unused */
2191 if (iconinfo->fIcon)
2193 info->ptHotSpot.x = ICON_HOTSPOT;
2194 info->ptHotSpot.y = ICON_HOTSPOT;
2196 else
2198 info->ptHotSpot.x = iconinfo->xHotspot;
2199 info->ptHotSpot.y = iconinfo->yHotspot;
2202 if (iconinfo->hbmColor)
2204 info->nWidth = bmpXor.dsBm.bmWidth;
2205 info->nHeight = bmpXor.dsBm.bmHeight;
2206 info->nWidthBytes = bmpXor.dsBm.bmWidthBytes;
2207 info->bPlanes = planes;
2208 info->bBitsPerPixel = bpp;
2210 else
2212 info->nWidth = bmpAnd.bmWidth;
2213 info->nHeight = bmpAnd.bmHeight / 2;
2214 info->nWidthBytes = get_bitmap_width_bytes(bmpAnd.bmWidth, 1);
2215 info->bPlanes = 1;
2216 info->bBitsPerPixel = 1;
2219 /* Transfer the bitmap bits to the CURSORICONINFO structure */
2221 /* Some apps pass a color bitmap as a mask, convert it to b/w */
2222 if (bmpAnd.bmBitsPixel == 1)
2224 GetBitmapBits( iconinfo->hbmMask, sizeAnd, (char*)(info + 1) );
2226 else
2228 HDC hdc, hdc_mem;
2229 HBITMAP hbmp_old, hbmp_mem_old, hbmp_mono;
2231 hdc = GetDC( 0 );
2232 hdc_mem = CreateCompatibleDC( hdc );
2234 hbmp_mono = CreateBitmap( bmpAnd.bmWidth, bmpAnd.bmHeight, 1, 1, NULL );
2236 hbmp_old = SelectObject( hdc, iconinfo->hbmMask );
2237 hbmp_mem_old = SelectObject( hdc_mem, hbmp_mono );
2239 BitBlt( hdc_mem, 0, 0, bmpAnd.bmWidth, bmpAnd.bmHeight, hdc, 0, 0, SRCCOPY );
2241 SelectObject( hdc, hbmp_old );
2242 SelectObject( hdc_mem, hbmp_mem_old );
2244 DeleteDC( hdc_mem );
2245 ReleaseDC( 0, hdc );
2247 GetBitmapBits( hbmp_mono, sizeAnd, (char*)(info + 1) );
2248 DeleteObject( hbmp_mono );
2251 if (iconinfo->hbmColor)
2253 char *dst_bits = (char*)(info + 1) + sizeAnd;
2255 if (bmpXor.dsBm.bmPlanes == planes && bmpXor.dsBm.bmBitsPixel == bpp)
2256 GetBitmapBits( iconinfo->hbmColor, sizeXor, dst_bits );
2257 else
2259 BITMAPINFO bminfo;
2260 int dib_width = get_dib_width_bytes( info->nWidth, info->bBitsPerPixel );
2261 int bitmap_width = get_bitmap_width_bytes( info->nWidth, info->bBitsPerPixel );
2263 bminfo.bmiHeader.biSize = sizeof(bminfo);
2264 bminfo.bmiHeader.biWidth = info->nWidth;
2265 bminfo.bmiHeader.biHeight = info->nHeight;
2266 bminfo.bmiHeader.biPlanes = info->bPlanes;
2267 bminfo.bmiHeader.biBitCount = info->bBitsPerPixel;
2268 bminfo.bmiHeader.biCompression = BI_RGB;
2269 bminfo.bmiHeader.biSizeImage = info->nHeight * dib_width;
2270 bminfo.bmiHeader.biXPelsPerMeter = 0;
2271 bminfo.bmiHeader.biYPelsPerMeter = 0;
2272 bminfo.bmiHeader.biClrUsed = 0;
2273 bminfo.bmiHeader.biClrImportant = 0;
2275 /* swap lines for dib sections */
2276 if (xor_objsize == sizeof(DIBSECTION))
2277 bminfo.bmiHeader.biHeight = -bminfo.bmiHeader.biHeight;
2279 if (dib_width != bitmap_width) /* need to fixup alignment */
2281 char *src_bits = HeapAlloc( GetProcessHeap(), 0, bminfo.bmiHeader.biSizeImage );
2283 if (src_bits && GetDIBits( screen_dc, iconinfo->hbmColor, 0, info->nHeight,
2284 src_bits, &bminfo, DIB_RGB_COLORS ))
2286 int y;
2287 for (y = 0; y < info->nHeight; y++)
2288 memcpy( dst_bits + y * bitmap_width, src_bits + y * dib_width, bitmap_width );
2290 HeapFree( GetProcessHeap(), 0, src_bits );
2292 else
2293 GetDIBits( screen_dc, iconinfo->hbmColor, 0, info->nHeight,
2294 dst_bits, &bminfo, DIB_RGB_COLORS );
2297 GlobalUnlock16( hObj );
2300 return create_cursor( 1, 0, hObj );
2303 /******************************************************************************
2304 * DrawIconEx (USER32.@) Draws an icon or cursor on device context
2306 * NOTES
2307 * Why is this using SM_CXICON instead of SM_CXCURSOR?
2309 * PARAMS
2310 * hdc [I] Handle to device context
2311 * x0 [I] X coordinate of upper left corner
2312 * y0 [I] Y coordinate of upper left corner
2313 * hIcon [I] Handle to icon to draw
2314 * cxWidth [I] Width of icon
2315 * cyWidth [I] Height of icon
2316 * istep [I] Index of frame in animated cursor
2317 * hbr [I] Handle to background brush
2318 * flags [I] Icon-drawing flags
2320 * RETURNS
2321 * Success: TRUE
2322 * Failure: FALSE
2324 BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
2325 INT cxWidth, INT cyWidth, UINT istep,
2326 HBRUSH hbr, UINT flags )
2328 CURSORICONINFO *ptr = GlobalLock16(HICON_16(hIcon));
2329 HDC hDC_off = 0, hMemDC;
2330 BOOL result = FALSE, DoOffscreen;
2331 HBITMAP hB_off = 0, hOld = 0;
2333 if (!ptr) return FALSE;
2334 TRACE_(icon)("(hdc=%p,pos=%d.%d,hicon=%p,extend=%d.%d,istep=%d,br=%p,flags=0x%08x)\n",
2335 hdc,x0,y0,hIcon,cxWidth,cyWidth,istep,hbr,flags );
2337 hMemDC = CreateCompatibleDC (hdc);
2338 if (istep)
2339 FIXME_(icon)("Ignoring istep=%d\n", istep);
2340 if (flags & DI_NOMIRROR)
2341 FIXME_(icon)("Ignoring flag DI_NOMIRROR\n");
2343 if (!flags) {
2344 FIXME_(icon)("no flags set? setting to DI_NORMAL\n");
2345 flags = DI_NORMAL;
2348 /* Calculate the size of the destination image. */
2349 if (cxWidth == 0)
2351 if (flags & DI_DEFAULTSIZE)
2352 cxWidth = GetSystemMetrics (SM_CXICON);
2353 else
2354 cxWidth = ptr->nWidth;
2356 if (cyWidth == 0)
2358 if (flags & DI_DEFAULTSIZE)
2359 cyWidth = GetSystemMetrics (SM_CYICON);
2360 else
2361 cyWidth = ptr->nHeight;
2364 DoOffscreen = (GetObjectType( hbr ) == OBJ_BRUSH);
2366 if (DoOffscreen) {
2367 RECT r;
2369 r.left = 0;
2370 r.top = 0;
2371 r.right = cxWidth;
2372 r.bottom = cxWidth;
2374 hDC_off = CreateCompatibleDC(hdc);
2375 hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth);
2376 if (hDC_off && hB_off) {
2377 hOld = SelectObject(hDC_off, hB_off);
2378 FillRect(hDC_off, &r, hbr);
2382 if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
2384 HBITMAP hXorBits, hAndBits;
2385 COLORREF oldFg, oldBg;
2386 INT nStretchMode;
2388 nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
2390 hXorBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
2391 ptr->bPlanes, ptr->bBitsPerPixel,
2392 (char *)(ptr + 1)
2393 + ptr->nHeight *
2394 get_bitmap_width_bytes(ptr->nWidth,1) );
2395 hAndBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
2396 1, 1, (char *)(ptr+1) );
2397 oldFg = SetTextColor( hdc, RGB(0,0,0) );
2398 oldBg = SetBkColor( hdc, RGB(255,255,255) );
2400 if (hXorBits && hAndBits)
2402 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
2403 if (flags & DI_MASK)
2405 if (DoOffscreen)
2406 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
2407 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
2408 else
2409 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
2410 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
2412 SelectObject( hMemDC, hXorBits );
2413 if (flags & DI_IMAGE)
2415 if (DoOffscreen)
2416 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
2417 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
2418 else
2419 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
2420 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
2422 SelectObject( hMemDC, hBitTemp );
2423 result = TRUE;
2426 SetTextColor( hdc, oldFg );
2427 SetBkColor( hdc, oldBg );
2428 if (hXorBits) DeleteObject( hXorBits );
2429 if (hAndBits) DeleteObject( hAndBits );
2430 SetStretchBltMode (hdc, nStretchMode);
2431 if (DoOffscreen) {
2432 BitBlt(hdc, x0, y0, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
2433 SelectObject(hDC_off, hOld);
2436 if (hMemDC) DeleteDC( hMemDC );
2437 if (hDC_off) DeleteDC(hDC_off);
2438 if (hB_off) DeleteObject(hB_off);
2439 GlobalUnlock16(HICON_16(hIcon));
2440 return result;
2443 /***********************************************************************
2444 * DIB_FixColorsToLoadflags
2446 * Change color table entries when LR_LOADTRANSPARENT or LR_LOADMAP3DCOLORS
2447 * are in loadflags
2449 static void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags, BYTE pix)
2451 int colors;
2452 COLORREF c_W, c_S, c_F, c_L, c_C;
2453 int incr,i;
2454 RGBQUAD *ptr;
2455 int bitmap_type;
2456 LONG width;
2457 LONG height;
2458 WORD bpp;
2459 DWORD compr;
2461 if (((bitmap_type = DIB_GetBitmapInfo((BITMAPINFOHEADER*) bmi, &width, &height, &bpp, &compr)) == -1))
2463 WARN_(resource)("Invalid bitmap\n");
2464 return;
2467 if (bpp > 8) return;
2469 if (bitmap_type == 0) /* BITMAPCOREHEADER */
2471 incr = 3;
2472 colors = 1 << bpp;
2474 else
2476 incr = 4;
2477 colors = bmi->bmiHeader.biClrUsed;
2478 if (colors > 256) colors = 256;
2479 if (!colors && (bpp <= 8)) colors = 1 << bpp;
2482 c_W = GetSysColor(COLOR_WINDOW);
2483 c_S = GetSysColor(COLOR_3DSHADOW);
2484 c_F = GetSysColor(COLOR_3DFACE);
2485 c_L = GetSysColor(COLOR_3DLIGHT);
2487 if (loadflags & LR_LOADTRANSPARENT) {
2488 switch (bpp) {
2489 case 1: pix = pix >> 7; break;
2490 case 4: pix = pix >> 4; break;
2491 case 8: break;
2492 default:
2493 WARN_(resource)("(%d): Unsupported depth\n", bpp);
2494 return;
2496 if (pix >= colors) {
2497 WARN_(resource)("pixel has color index greater than biClrUsed!\n");
2498 return;
2500 if (loadflags & LR_LOADMAP3DCOLORS) c_W = c_F;
2501 ptr = (RGBQUAD*)((char*)bmi->bmiColors+pix*incr);
2502 ptr->rgbBlue = GetBValue(c_W);
2503 ptr->rgbGreen = GetGValue(c_W);
2504 ptr->rgbRed = GetRValue(c_W);
2506 if (loadflags & LR_LOADMAP3DCOLORS)
2507 for (i=0; i<colors; i++) {
2508 ptr = (RGBQUAD*)((char*)bmi->bmiColors+i*incr);
2509 c_C = RGB(ptr->rgbRed, ptr->rgbGreen, ptr->rgbBlue);
2510 if (c_C == RGB(128, 128, 128)) {
2511 ptr->rgbRed = GetRValue(c_S);
2512 ptr->rgbGreen = GetGValue(c_S);
2513 ptr->rgbBlue = GetBValue(c_S);
2514 } else if (c_C == RGB(192, 192, 192)) {
2515 ptr->rgbRed = GetRValue(c_F);
2516 ptr->rgbGreen = GetGValue(c_F);
2517 ptr->rgbBlue = GetBValue(c_F);
2518 } else if (c_C == RGB(223, 223, 223)) {
2519 ptr->rgbRed = GetRValue(c_L);
2520 ptr->rgbGreen = GetGValue(c_L);
2521 ptr->rgbBlue = GetBValue(c_L);
2527 /**********************************************************************
2528 * BITMAP_Load
2530 static HBITMAP BITMAP_Load( HINSTANCE instance, LPCWSTR name,
2531 INT desiredx, INT desiredy, UINT loadflags )
2533 HBITMAP hbitmap = 0, orig_bm;
2534 HRSRC hRsrc;
2535 HGLOBAL handle;
2536 char *ptr = NULL;
2537 BITMAPINFO *info, *fix_info = NULL, *scaled_info = NULL;
2538 int size;
2539 BYTE pix;
2540 char *bits;
2541 LONG width, height, new_width, new_height;
2542 WORD bpp_dummy;
2543 DWORD compr_dummy;
2544 INT bm_type;
2545 HDC screen_mem_dc = NULL;
2547 if (!(loadflags & LR_LOADFROMFILE))
2549 if (!instance)
2551 /* OEM bitmap: try to load the resource from user32.dll */
2552 instance = user32_module;
2555 if (!(hRsrc = FindResourceW( instance, name, (LPWSTR)RT_BITMAP ))) return 0;
2556 if (!(handle = LoadResource( instance, hRsrc ))) return 0;
2558 if ((info = LockResource( handle )) == NULL) return 0;
2560 else
2562 BITMAPFILEHEADER * bmfh;
2564 if (!(ptr = map_fileW( name, NULL ))) return 0;
2565 info = (BITMAPINFO *)(ptr + sizeof(BITMAPFILEHEADER));
2566 bmfh = (BITMAPFILEHEADER *)ptr;
2567 if (!( bmfh->bfType == 0x4d42 /* 'BM' */ &&
2568 bmfh->bfReserved1 == 0 &&
2569 bmfh->bfReserved2 == 0))
2571 WARN("Invalid/unsupported bitmap format!\n");
2572 UnmapViewOfFile( ptr );
2573 return 0;
2577 size = bitmap_info_size(info, DIB_RGB_COLORS);
2578 fix_info = HeapAlloc(GetProcessHeap(), 0, size);
2579 scaled_info = HeapAlloc(GetProcessHeap(), 0, size);
2581 if (!fix_info || !scaled_info) goto end;
2582 memcpy(fix_info, info, size);
2584 pix = *((LPBYTE)info + size);
2585 DIB_FixColorsToLoadflags(fix_info, loadflags, pix);
2587 memcpy(scaled_info, fix_info, size);
2588 bm_type = DIB_GetBitmapInfo( &fix_info->bmiHeader, &width, &height,
2589 &bpp_dummy, &compr_dummy);
2590 if(desiredx != 0)
2591 new_width = desiredx;
2592 else
2593 new_width = width;
2595 if(desiredy != 0)
2596 new_height = height > 0 ? desiredy : -desiredy;
2597 else
2598 new_height = height;
2600 if(bm_type == 0)
2602 BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)&scaled_info->bmiHeader;
2603 core->bcWidth = new_width;
2604 core->bcHeight = new_height;
2606 else
2608 scaled_info->bmiHeader.biWidth = new_width;
2609 scaled_info->bmiHeader.biHeight = new_height;
2612 if (new_height < 0) new_height = -new_height;
2614 if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
2615 if (!(screen_mem_dc = CreateCompatibleDC( screen_dc ))) goto end;
2617 bits = (char *)info + size;
2619 if (loadflags & LR_CREATEDIBSECTION)
2621 scaled_info->bmiHeader.biCompression = 0; /* DIBSection can't be compressed */
2622 hbitmap = CreateDIBSection(screen_dc, scaled_info, DIB_RGB_COLORS, NULL, 0, 0);
2624 else
2626 if (is_dib_monochrome(fix_info))
2627 hbitmap = CreateBitmap(new_width, new_height, 1, 1, NULL);
2628 else
2629 hbitmap = CreateCompatibleBitmap(screen_dc, new_width, new_height);
2632 orig_bm = SelectObject(screen_mem_dc, hbitmap);
2633 StretchDIBits(screen_mem_dc, 0, 0, new_width, new_height, 0, 0, width, height, bits, fix_info, DIB_RGB_COLORS, SRCCOPY);
2634 SelectObject(screen_mem_dc, orig_bm);
2636 end:
2637 if (screen_mem_dc) DeleteDC(screen_mem_dc);
2638 HeapFree(GetProcessHeap(), 0, scaled_info);
2639 HeapFree(GetProcessHeap(), 0, fix_info);
2640 if (loadflags & LR_LOADFROMFILE) UnmapViewOfFile( ptr );
2642 return hbitmap;
2645 /**********************************************************************
2646 * LoadImageA (USER32.@)
2648 * See LoadImageW.
2650 HANDLE WINAPI LoadImageA( HINSTANCE hinst, LPCSTR name, UINT type,
2651 INT desiredx, INT desiredy, UINT loadflags)
2653 HANDLE res;
2654 LPWSTR u_name;
2656 if (!HIWORD(name))
2657 return LoadImageW(hinst, (LPCWSTR)name, type, desiredx, desiredy, loadflags);
2659 __TRY {
2660 DWORD len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
2661 u_name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2662 MultiByteToWideChar( CP_ACP, 0, name, -1, u_name, len );
2664 __EXCEPT_PAGE_FAULT {
2665 SetLastError( ERROR_INVALID_PARAMETER );
2666 return 0;
2668 __ENDTRY
2669 res = LoadImageW(hinst, u_name, type, desiredx, desiredy, loadflags);
2670 HeapFree(GetProcessHeap(), 0, u_name);
2671 return res;
2675 /******************************************************************************
2676 * LoadImageW (USER32.@) Loads an icon, cursor, or bitmap
2678 * PARAMS
2679 * hinst [I] Handle of instance that contains image
2680 * name [I] Name of image
2681 * type [I] Type of image
2682 * desiredx [I] Desired width
2683 * desiredy [I] Desired height
2684 * loadflags [I] Load flags
2686 * RETURNS
2687 * Success: Handle to newly loaded image
2688 * Failure: NULL
2690 * FIXME: Implementation lacks some features, see LR_ defines in winuser.h
2692 HANDLE WINAPI LoadImageW( HINSTANCE hinst, LPCWSTR name, UINT type,
2693 INT desiredx, INT desiredy, UINT loadflags )
2695 TRACE_(resource)("(%p,%s,%d,%d,%d,0x%08x)\n",
2696 hinst,debugstr_w(name),type,desiredx,desiredy,loadflags);
2698 if (loadflags & LR_DEFAULTSIZE) {
2699 if (type == IMAGE_ICON) {
2700 if (!desiredx) desiredx = GetSystemMetrics(SM_CXICON);
2701 if (!desiredy) desiredy = GetSystemMetrics(SM_CYICON);
2702 } else if (type == IMAGE_CURSOR) {
2703 if (!desiredx) desiredx = GetSystemMetrics(SM_CXCURSOR);
2704 if (!desiredy) desiredy = GetSystemMetrics(SM_CYCURSOR);
2707 if (loadflags & LR_LOADFROMFILE) loadflags &= ~LR_SHARED;
2708 switch (type) {
2709 case IMAGE_BITMAP:
2710 return BITMAP_Load( hinst, name, desiredx, desiredy, loadflags );
2712 case IMAGE_ICON:
2713 if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
2714 if (screen_dc)
2716 UINT palEnts = GetSystemPaletteEntries(screen_dc, 0, 0, NULL);
2717 if (palEnts == 0) palEnts = 256;
2718 return CURSORICON_Load(hinst, name, desiredx, desiredy,
2719 palEnts, FALSE, loadflags);
2721 break;
2723 case IMAGE_CURSOR:
2724 return CURSORICON_Load(hinst, name, desiredx, desiredy,
2725 1, TRUE, loadflags);
2727 return 0;
2730 /******************************************************************************
2731 * CopyImage (USER32.@) Creates new image and copies attributes to it
2733 * PARAMS
2734 * hnd [I] Handle to image to copy
2735 * type [I] Type of image to copy
2736 * desiredx [I] Desired width of new image
2737 * desiredy [I] Desired height of new image
2738 * flags [I] Copy flags
2740 * RETURNS
2741 * Success: Handle to newly created image
2742 * Failure: NULL
2744 * BUGS
2745 * Only Windows NT 4.0 supports the LR_COPYRETURNORG flag for bitmaps,
2746 * all other versions (95/2000/XP have been tested) ignore it.
2748 * NOTES
2749 * If LR_CREATEDIBSECTION is absent, the copy will be monochrome for
2750 * a monochrome source bitmap or if LR_MONOCHROME is present, otherwise
2751 * the copy will have the same depth as the screen.
2752 * The content of the image will only be copied if the bit depth of the
2753 * original image is compatible with the bit depth of the screen, or
2754 * if the source is a DIB section.
2755 * The LR_MONOCHROME flag is ignored if LR_CREATEDIBSECTION is present.
2757 HANDLE WINAPI CopyImage( HANDLE hnd, UINT type, INT desiredx,
2758 INT desiredy, UINT flags )
2760 TRACE("hnd=%p, type=%u, desiredx=%d, desiredy=%d, flags=%x\n",
2761 hnd, type, desiredx, desiredy, flags);
2763 switch (type)
2765 case IMAGE_BITMAP:
2767 HBITMAP res = NULL;
2768 DIBSECTION ds;
2769 int objSize;
2770 BITMAPINFO * bi;
2772 objSize = GetObjectW( hnd, sizeof(ds), &ds );
2773 if (!objSize) return 0;
2774 if ((desiredx < 0) || (desiredy < 0)) return 0;
2776 if (flags & LR_COPYFROMRESOURCE)
2778 FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
2781 if (desiredx == 0) desiredx = ds.dsBm.bmWidth;
2782 if (desiredy == 0) desiredy = ds.dsBm.bmHeight;
2784 /* Allocate memory for a BITMAPINFOHEADER structure and a
2785 color table. The maximum number of colors in a color table
2786 is 256 which corresponds to a bitmap with depth 8.
2787 Bitmaps with higher depths don't have color tables. */
2788 bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2789 if (!bi) return 0;
2791 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
2792 bi->bmiHeader.biPlanes = ds.dsBm.bmPlanes;
2793 bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
2794 bi->bmiHeader.biCompression = BI_RGB;
2796 if (flags & LR_CREATEDIBSECTION)
2798 /* Create a DIB section. LR_MONOCHROME is ignored */
2799 void * bits;
2800 HDC dc = CreateCompatibleDC(NULL);
2802 if (objSize == sizeof(DIBSECTION))
2804 /* The source bitmap is a DIB.
2805 Get its attributes to create an exact copy */
2806 memcpy(bi, &ds.dsBmih, sizeof(BITMAPINFOHEADER));
2809 /* Get the color table or the color masks */
2810 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
2812 bi->bmiHeader.biWidth = desiredx;
2813 bi->bmiHeader.biHeight = desiredy;
2814 bi->bmiHeader.biSizeImage = 0;
2816 res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
2817 DeleteDC(dc);
2819 else
2821 /* Create a device-dependent bitmap */
2823 BOOL monochrome = (flags & LR_MONOCHROME);
2825 if (objSize == sizeof(DIBSECTION))
2827 /* The source bitmap is a DIB section.
2828 Get its attributes */
2829 HDC dc = CreateCompatibleDC(NULL);
2830 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
2831 bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
2832 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
2833 DeleteDC(dc);
2835 if (!monochrome && ds.dsBm.bmBitsPixel == 1)
2837 /* Look if the colors of the DIB are black and white */
2839 monochrome =
2840 (bi->bmiColors[0].rgbRed == 0xff
2841 && bi->bmiColors[0].rgbGreen == 0xff
2842 && bi->bmiColors[0].rgbBlue == 0xff
2843 && bi->bmiColors[0].rgbReserved == 0
2844 && bi->bmiColors[1].rgbRed == 0
2845 && bi->bmiColors[1].rgbGreen == 0
2846 && bi->bmiColors[1].rgbBlue == 0
2847 && bi->bmiColors[1].rgbReserved == 0)
2849 (bi->bmiColors[0].rgbRed == 0
2850 && bi->bmiColors[0].rgbGreen == 0
2851 && bi->bmiColors[0].rgbBlue == 0
2852 && bi->bmiColors[0].rgbReserved == 0
2853 && bi->bmiColors[1].rgbRed == 0xff
2854 && bi->bmiColors[1].rgbGreen == 0xff
2855 && bi->bmiColors[1].rgbBlue == 0xff
2856 && bi->bmiColors[1].rgbReserved == 0);
2859 else if (!monochrome)
2861 monochrome = ds.dsBm.bmBitsPixel == 1;
2864 if (monochrome)
2866 res = CreateBitmap(desiredx, desiredy, 1, 1, NULL);
2868 else
2870 HDC screenDC = GetDC(NULL);
2871 res = CreateCompatibleBitmap(screenDC, desiredx, desiredy);
2872 ReleaseDC(NULL, screenDC);
2876 if (res)
2878 /* Only copy the bitmap if it's a DIB section or if it's
2879 compatible to the screen */
2880 BOOL copyContents;
2882 if (objSize == sizeof(DIBSECTION))
2884 copyContents = TRUE;
2886 else
2888 HDC screenDC = GetDC(NULL);
2889 int screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
2890 ReleaseDC(NULL, screenDC);
2892 copyContents = (ds.dsBm.bmBitsPixel == 1 || ds.dsBm.bmBitsPixel == screen_depth);
2895 if (copyContents)
2897 /* The source bitmap may already be selected in a device context,
2898 use GetDIBits/StretchDIBits and not StretchBlt */
2900 HDC dc;
2901 void * bits;
2903 dc = CreateCompatibleDC(NULL);
2905 bi->bmiHeader.biWidth = ds.dsBm.bmWidth;
2906 bi->bmiHeader.biHeight = ds.dsBm.bmHeight;
2907 bi->bmiHeader.biSizeImage = 0;
2908 bi->bmiHeader.biClrUsed = 0;
2909 bi->bmiHeader.biClrImportant = 0;
2911 /* Fill in biSizeImage */
2912 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
2913 bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bi->bmiHeader.biSizeImage);
2915 if (bits)
2917 HBITMAP oldBmp;
2919 /* Get the image bits of the source bitmap */
2920 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS);
2922 /* Copy it to the destination bitmap */
2923 oldBmp = SelectObject(dc, res);
2924 StretchDIBits(dc, 0, 0, desiredx, desiredy,
2925 0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight,
2926 bits, bi, DIB_RGB_COLORS, SRCCOPY);
2927 SelectObject(dc, oldBmp);
2929 HeapFree(GetProcessHeap(), 0, bits);
2932 DeleteDC(dc);
2935 if (flags & LR_COPYDELETEORG)
2937 DeleteObject(hnd);
2940 HeapFree(GetProcessHeap(), 0, bi);
2941 return res;
2943 case IMAGE_ICON:
2944 return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags);
2945 case IMAGE_CURSOR:
2946 /* Should call CURSORICON_ExtCopy but more testing
2947 * needs to be done before we change this
2949 if (flags) FIXME("Flags are ignored\n");
2950 return CopyCursor(hnd);
2952 return 0;
2956 /******************************************************************************
2957 * LoadBitmapW (USER32.@) Loads bitmap from the executable file
2959 * RETURNS
2960 * Success: Handle to specified bitmap
2961 * Failure: NULL
2963 HBITMAP WINAPI LoadBitmapW(
2964 HINSTANCE instance, /* [in] Handle to application instance */
2965 LPCWSTR name) /* [in] Address of bitmap resource name */
2967 return LoadImageW( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2970 /**********************************************************************
2971 * LoadBitmapA (USER32.@)
2973 * See LoadBitmapW.
2975 HBITMAP WINAPI LoadBitmapA( HINSTANCE instance, LPCSTR name )
2977 return LoadImageA( instance, name, IMAGE_BITMAP, 0, 0, 0 );