[03/10] user: Use 32-bit cursor handles
[wine/hacks.git] / dlls / user32 / cursoricon.c
blob21ba8e84fb045ec90b7f24ea79e92ba574107717
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 * 32-bit cursors and icons are stored in the server.
30 * 16-bit cursors and icons are stored in a global heap block, with the
31 * following layout:
33 * CURSORICONINFO info;
34 * BYTE[] ANDbits;
35 * BYTE[] XORbits;
37 * The bits structures are in the format of a device-dependent bitmap.
39 * This layout is very sub-optimal, as the bitmap bits are stored in
40 * the X client instead of in the server like other bitmaps; however,
41 * some programs (notably Paint Brush) expect to be able to manipulate
42 * the bits directly :-(
45 #include "config.h"
46 #include "wine/port.h"
48 #include <stdarg.h>
49 #include <string.h>
50 #include <stdlib.h>
52 #include "ntstatus.h"
53 #define WIN32_NO_STATUS
54 #include "winternl.h"
55 #include "windef.h"
56 #include "winbase.h"
57 #include "wingdi.h"
58 #include "winerror.h"
59 #include "wine/winbase16.h"
60 #include "wine/winuser16.h"
61 #include "wine/exception.h"
62 #include "wine/debug.h"
63 #include "wine/list.h"
64 #include "wine/server.h"
65 #include "user_private.h"
67 WINE_DEFAULT_DEBUG_CHANNEL(cursor);
68 WINE_DECLARE_DEBUG_CHANNEL(icon);
69 WINE_DECLARE_DEBUG_CHANNEL(resource);
71 #include "pshpack1.h"
73 typedef struct {
74 BYTE bWidth;
75 BYTE bHeight;
76 BYTE bColorCount;
77 BYTE bReserved;
78 WORD xHotspot;
79 WORD yHotspot;
80 DWORD dwDIBSize;
81 DWORD dwDIBOffset;
82 } CURSORICONFILEDIRENTRY;
84 typedef struct
86 WORD idReserved;
87 WORD idType;
88 WORD idCount;
89 CURSORICONFILEDIRENTRY idEntries[1];
90 } CURSORICONFILEDIR;
92 #include "poppack.h"
94 #define CID_RESOURCE 0x0001
95 #define CID_WIN32 0x0004
96 #define CID_NONSHARED 0x0008
98 static RECT CURSOR_ClipRect; /* Cursor clipping rect */
100 static HDC screen_dc;
102 static const WCHAR DISPLAYW[] = {'D','I','S','P','L','A','Y',0};
104 /**********************************************************************
105 * ICONCACHE for cursors/icons loaded with LR_SHARED.
107 * FIXME: This should not be allocated on the system heap, but on a
108 * subsystem-global heap (i.e. one for all Win16 processes,
109 * and one for each Win32 process).
111 typedef struct tagICONCACHE
113 struct tagICONCACHE *next;
115 HMODULE hModule;
116 HRSRC hRsrc;
117 HRSRC hGroupRsrc;
118 HICON hIcon;
120 INT count;
122 } ICONCACHE;
124 static ICONCACHE *IconAnchor = NULL;
126 static CRITICAL_SECTION IconCrst;
127 static CRITICAL_SECTION_DEBUG critsect_debug =
129 0, 0, &IconCrst,
130 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
131 0, 0, { (DWORD_PTR)(__FILE__ ": IconCrst") }
133 static CRITICAL_SECTION IconCrst = { &critsect_debug, -1, 0, 0, 0, 0 };
135 static const WORD ICON_HOTSPOT = 0x4242;
137 /* What is a good table size? */
138 #define CURSOR_HASH_SIZE 97
140 typedef struct {
141 HCURSOR16 cursor16;
142 HCURSOR cursor32;
143 struct list entry16;
144 struct list entry32;
145 } cursor_map_entry_t;
147 static struct list cursor16to32[CURSOR_HASH_SIZE];
148 static struct list cursor32to16[CURSOR_HASH_SIZE];
150 static inline int hash_cursor_handle( DWORD handle )
152 return handle % CURSOR_HASH_SIZE;
155 static void add_cursor16to32_entry( cursor_map_entry_t *entry )
157 int idx = hash_cursor_handle( entry->cursor16 );
159 if (!cursor16to32[idx].next) list_init( &cursor16to32[idx] );
161 list_add_head( &cursor16to32[idx], &entry->entry16 );
164 static void add_cursor32to16_entry( cursor_map_entry_t *entry )
166 int idx = hash_cursor_handle( (DWORD)entry->cursor32 );
168 if (!cursor32to16[idx].next) list_init( &cursor32to16[idx] );
170 list_add_head( &cursor32to16[idx], &entry->entry32 );
173 static cursor_map_entry_t *remove_cursor16to32_entry( HCURSOR16 cursor16 )
175 cursor_map_entry_t *entry = NULL;
176 int idx = hash_cursor_handle( cursor16 );
178 if (cursor16to32[idx].next)
180 LIST_FOR_EACH_ENTRY( entry, &cursor16to32[idx], cursor_map_entry_t, entry16 )
181 if (entry->cursor16 == cursor16)
183 list_remove( &entry->entry16 );
184 return entry;
188 return entry;
191 static cursor_map_entry_t *remove_cursor32to16_entry( HCURSOR cursor32 )
193 cursor_map_entry_t *entry = NULL;
194 int idx = hash_cursor_handle( (DWORD)cursor32 );
196 if (cursor32to16[idx].next)
198 LIST_FOR_EACH_ENTRY( entry, &cursor32to16[idx], cursor_map_entry_t, entry32 )
199 if (entry->cursor32 == cursor32)
201 list_remove( &entry->entry32 );
202 return entry;
206 return entry;
209 /* Ask the server for a cursor */
210 static HCURSOR create_cursor( unsigned int num_frames, unsigned int delay )
212 HCURSOR cursor = 0;
214 SERVER_START_REQ(create_cursor)
216 req->num_frames = num_frames;
217 req->delay = delay;
218 if (!wine_server_call_err( req )) cursor = reply->handle;
220 SERVER_END_REQ;
222 return cursor;
225 /* Tell the server to kill a cursor */
226 static HCURSOR16 destroy_cursor( HCURSOR cursor )
228 cursor_map_entry_t *entry;
229 HCURSOR16 cursor16 = 0;
231 if (!cursor) return 0;
233 SERVER_START_REQ(destroy_cursor)
235 req->handle = cursor;
236 wine_server_call( req );
238 SERVER_END_REQ;
240 entry = remove_cursor32to16_entry( cursor );
241 if (entry)
243 cursor16 = entry->cursor16;
244 remove_cursor16to32_entry( cursor16 );
245 HeapFree( GetProcessHeap(), 0, entry );
248 return GlobalFree16( cursor16 );
251 /* Upload a cursor frame to the server */
252 static void set_cursor_frame( HCURSOR cursor, unsigned int frame_idx, cursor_frame_t *frame )
254 SERVER_START_REQ(set_cursor_frame)
256 req->handle = cursor;
257 req->frame_idx = frame_idx;
258 req->xhot = frame->xhot;
259 req->yhot = frame->yhot;
260 req->width = frame->width;
261 req->height = frame->height;
262 req->and_width_bytes = frame->and_width_bytes;
263 req->xor_width_bytes = frame->xor_width_bytes;
264 req->planes = frame->planes;
265 req->bpp = frame->bpp;
266 wine_server_add_data( req, frame->bits, (frame->and_width_bytes + frame->xor_width_bytes) * frame->height );
267 wine_server_call( req );
269 SERVER_END_REQ;
272 /* Download a cursor frame from the server */
273 static BOOL get_cursor_frame( HCURSOR cursor, unsigned int frame_idx, cursor_frame_t *frame )
275 NTSTATUS res;
276 /* Enough for a 32-bits 32x32 cursor / icon. */
277 unsigned int buffer_size = 4224;
278 unsigned int count = 0;
282 frame->bits = HeapAlloc(GetProcessHeap(), 0, buffer_size);
283 SERVER_START_REQ(get_cursor_frame)
285 req->handle = cursor;
286 req->frame_idx = frame_idx;
287 wine_server_set_reply( req, frame->bits, buffer_size);
288 if (!(res = wine_server_call_err( req )))
290 frame->xhot = reply->xhot;
291 frame->yhot = reply->yhot;
292 frame->width = reply->width;
293 frame->height = reply->height;
294 frame->and_width_bytes = reply->and_width_bytes;
295 frame->xor_width_bytes = reply->xor_width_bytes;
296 frame->planes = reply->planes;
297 frame->bpp = reply->bpp;
298 } else {
299 HeapFree( GetProcessHeap(), 0, frame->bits );
300 buffer_size = (reply->and_width_bytes + reply->xor_width_bytes) * reply->height;
303 SERVER_END_REQ;
304 } while (res == STATUS_BUFFER_OVERFLOW && !count++);
306 if (!frame->height)
308 HeapFree( GetProcessHeap(), 0, frame->bits );
310 return FALSE;
313 return TRUE;
316 /* Lookup the cursor's 16-bit handle. Create one if it doesn't already exist. */
317 HCURSOR16 get_cursor_handle16( HCURSOR cursor32, BOOL create )
319 cursor_map_entry_t *entry;
320 int idx = hash_cursor_handle( (DWORD)cursor32 );
322 if (!cursor32) return 0;
324 if (cursor32to16[idx].next)
326 LIST_FOR_EACH_ENTRY( entry, &cursor32to16[idx], cursor_map_entry_t, entry32 )
327 if (entry->cursor32 == cursor32) return entry->cursor16;
330 /* 16-bit cursor handle not found, create one */
331 if (create)
333 size_t bits_size;
334 HCURSOR16 cursor16;
335 cursor_frame_t frame;
337 if (!get_cursor_frame( cursor32, 0, &frame )) return 0;
339 entry = HeapAlloc( GetProcessHeap(), 0, sizeof(cursor_map_entry_t) );
340 bits_size = (frame.and_width_bytes + frame.xor_width_bytes) * frame.height;
341 cursor16 = GlobalAlloc16( GMEM_MOVEABLE, sizeof(CURSORICONINFO) + bits_size );
342 if (cursor16)
344 CURSORICONINFO *info;
346 info = (CURSORICONINFO *)GlobalLock16( cursor16 );
347 info->ptHotSpot.x = frame.xhot;
348 info->ptHotSpot.y = frame.yhot;
349 info->nWidth = frame.width;
350 info->nHeight = frame.height;
351 info->nWidthBytes = frame.xor_width_bytes;
352 info->bPlanes = frame.planes;
353 info->bBitsPerPixel = frame.bpp;
354 CopyMemory( info + 1, frame.bits, bits_size );
355 GlobalUnlock16( cursor16 );
357 HeapFree( GetProcessHeap(), 0, frame.bits );
359 entry->cursor16 = cursor16;
360 entry->cursor32 = cursor32;
361 add_cursor16to32_entry( entry );
362 add_cursor32to16_entry( entry );
364 return cursor16;
367 return 0;
370 HCURSOR get_cursor_handle32( HCURSOR16 cursor16 )
372 cursor_map_entry_t *entry;
373 int idx = hash_cursor_handle( cursor16 );
375 if (!cursor16) return 0;
377 if (cursor16to32[idx].next)
379 LIST_FOR_EACH_ENTRY( entry, &cursor16to32[idx], cursor_map_entry_t, entry16 )
380 if (entry->cursor16 == cursor16) return entry->cursor32;
383 return 0;
386 /***********************************************************************
387 * map_fileW
389 * Helper function to map a file to memory:
390 * name - file name
391 * [RETURN] ptr - pointer to mapped file
392 * [RETURN] filesize - pointer size of file to be stored if not NULL
394 static void *map_fileW( LPCWSTR name, LPDWORD filesize )
396 HANDLE hFile, hMapping;
397 LPVOID ptr = NULL;
399 hFile = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL,
400 OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0 );
401 if (hFile != INVALID_HANDLE_VALUE)
403 hMapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
404 if (hMapping)
406 ptr = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
407 CloseHandle( hMapping );
408 if (filesize)
409 *filesize = GetFileSize( hFile, NULL );
411 CloseHandle( hFile );
413 return ptr;
417 /***********************************************************************
418 * get_bitmap_width_bytes
420 * Return number of bytes taken by a scanline of 16-bit aligned Windows DDB
421 * data.
423 static int get_bitmap_width_bytes( int width, int bpp )
425 switch(bpp)
427 case 1:
428 return 2 * ((width+15) / 16);
429 case 4:
430 return 2 * ((width+3) / 4);
431 case 24:
432 width *= 3;
433 /* fall through */
434 case 8:
435 return width + (width & 1);
436 case 16:
437 case 15:
438 return width * 2;
439 case 32:
440 return width * 4;
441 default:
442 WARN("Unknown depth %d, please report.\n", bpp );
444 return -1;
448 /***********************************************************************
449 * get_dib_width_bytes
451 * Return the width of a DIB bitmap in bytes. DIB bitmap data is 32-bit aligned.
453 static int get_dib_width_bytes( int width, int depth )
455 int words;
457 switch(depth)
459 case 1: words = (width + 31) / 32; break;
460 case 4: words = (width + 7) / 8; break;
461 case 8: words = (width + 3) / 4; break;
462 case 15:
463 case 16: words = (width + 1) / 2; break;
464 case 24: words = (width * 3 + 3)/4; break;
465 default:
466 WARN("(%d): Unsupported depth\n", depth );
467 /* fall through */
468 case 32:
469 words = width;
471 return 4 * words;
475 /***********************************************************************
476 * bitmap_info_size
478 * Return the size of the bitmap info structure including color table.
480 static int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
482 int colors, masks = 0;
484 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
486 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
487 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
488 return sizeof(BITMAPCOREHEADER) + colors *
489 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
491 else /* assume BITMAPINFOHEADER */
493 colors = info->bmiHeader.biClrUsed;
494 if (colors > 256) /* buffer overflow otherwise */
495 colors = 256;
496 if (!colors && (info->bmiHeader.biBitCount <= 8))
497 colors = 1 << info->bmiHeader.biBitCount;
498 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
499 return sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) + colors *
500 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
505 /***********************************************************************
506 * is_dib_monochrome
508 * Returns whether a DIB can be converted to a monochrome DDB.
510 * A DIB can be converted if its color table contains only black and
511 * white. Black must be the first color in the color table.
513 * Note : If the first color in the color table is white followed by
514 * black, we can't convert it to a monochrome DDB with
515 * SetDIBits, because black and white would be inverted.
517 static BOOL is_dib_monochrome( const BITMAPINFO* info )
519 if (info->bmiHeader.biBitCount != 1) return FALSE;
521 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
523 const RGBTRIPLE *rgb = ((const BITMAPCOREINFO*)info)->bmciColors;
525 /* Check if the first color is black */
526 if ((rgb->rgbtRed == 0) && (rgb->rgbtGreen == 0) && (rgb->rgbtBlue == 0))
528 rgb++;
530 /* Check if the second color is white */
531 return ((rgb->rgbtRed == 0xff) && (rgb->rgbtGreen == 0xff)
532 && (rgb->rgbtBlue == 0xff));
534 else return FALSE;
536 else /* assume BITMAPINFOHEADER */
538 const RGBQUAD *rgb = info->bmiColors;
540 /* Check if the first color is black */
541 if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) &&
542 (rgb->rgbBlue == 0) && (rgb->rgbReserved == 0))
544 rgb++;
546 /* Check if the second color is white */
547 return ((rgb->rgbRed == 0xff) && (rgb->rgbGreen == 0xff)
548 && (rgb->rgbBlue == 0xff) && (rgb->rgbReserved == 0));
550 else return FALSE;
554 /***********************************************************************
555 * DIB_GetBitmapInfo
557 * Get the info from a bitmap header.
558 * Return 1 for INFOHEADER, 0 for COREHEADER,
559 * 4 for V4HEADER, 5 for V5HEADER, -1 for error.
561 static int DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width,
562 LONG *height, WORD *bpp, DWORD *compr )
564 if (header->biSize == sizeof(BITMAPINFOHEADER))
566 *width = header->biWidth;
567 *height = header->biHeight;
568 *bpp = header->biBitCount;
569 *compr = header->biCompression;
570 return 1;
572 if (header->biSize == sizeof(BITMAPCOREHEADER))
574 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header;
575 *width = core->bcWidth;
576 *height = core->bcHeight;
577 *bpp = core->bcBitCount;
578 *compr = 0;
579 return 0;
581 if (header->biSize == sizeof(BITMAPV4HEADER))
583 const BITMAPV4HEADER *v4hdr = (const BITMAPV4HEADER *)header;
584 *width = v4hdr->bV4Width;
585 *height = v4hdr->bV4Height;
586 *bpp = v4hdr->bV4BitCount;
587 *compr = v4hdr->bV4V4Compression;
588 return 4;
590 if (header->biSize == sizeof(BITMAPV5HEADER))
592 const BITMAPV5HEADER *v5hdr = (const BITMAPV5HEADER *)header;
593 *width = v5hdr->bV5Width;
594 *height = v5hdr->bV5Height;
595 *bpp = v5hdr->bV5BitCount;
596 *compr = v5hdr->bV5Compression;
597 return 5;
599 ERR("(%d): unknown/wrong size for header\n", header->biSize );
600 return -1;
603 /**********************************************************************
604 * CURSORICON_FindSharedIcon
606 static HICON CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
608 HICON hIcon = 0;
609 ICONCACHE *ptr;
611 EnterCriticalSection( &IconCrst );
613 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
614 if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
616 ptr->count++;
617 hIcon = ptr->hIcon;
618 break;
621 LeaveCriticalSection( &IconCrst );
623 return hIcon;
626 /*************************************************************************
627 * CURSORICON_FindCache
629 * Given a handle, find the corresponding cache element
631 * PARAMS
632 * Handle [I] handle to an Image
634 * RETURNS
635 * Success: The cache entry
636 * Failure: NULL
639 static ICONCACHE* CURSORICON_FindCache(HICON hIcon)
641 ICONCACHE *ptr;
642 ICONCACHE *pRet=NULL;
643 BOOL IsFound = FALSE;
645 EnterCriticalSection( &IconCrst );
647 for (ptr = IconAnchor; ptr != NULL && !IsFound; ptr = ptr->next)
649 if ( hIcon == ptr->hIcon )
651 IsFound = TRUE;
652 pRet = ptr;
656 LeaveCriticalSection( &IconCrst );
658 return pRet;
661 /**********************************************************************
662 * CURSORICON_AddSharedIcon
664 static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HRSRC hGroupRsrc, HICON hIcon )
666 ICONCACHE *ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(ICONCACHE) );
667 if ( !ptr ) return;
669 ptr->hModule = hModule;
670 ptr->hRsrc = hRsrc;
671 ptr->hIcon = hIcon;
672 ptr->hGroupRsrc = hGroupRsrc;
673 ptr->count = 1;
675 EnterCriticalSection( &IconCrst );
676 ptr->next = IconAnchor;
677 IconAnchor = ptr;
678 LeaveCriticalSection( &IconCrst );
681 /**********************************************************************
682 * CURSORICON_DelSharedIcon
684 static INT CURSORICON_DelSharedIcon( HICON hIcon )
686 INT count = -1;
687 ICONCACHE *ptr;
689 EnterCriticalSection( &IconCrst );
691 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
692 if ( ptr->hIcon == hIcon )
694 if ( ptr->count > 0 ) ptr->count--;
695 count = ptr->count;
696 break;
699 LeaveCriticalSection( &IconCrst );
701 return count;
704 /**********************************************************************
705 * CURSORICON_FreeModuleIcons
707 void CURSORICON_FreeModuleIcons( HMODULE16 hMod16 )
709 ICONCACHE **ptr = &IconAnchor;
710 HMODULE hModule = HMODULE_32(GetExePtr( hMod16 ));
712 EnterCriticalSection( &IconCrst );
714 while ( *ptr )
716 if ( (*ptr)->hModule == hModule )
718 ICONCACHE *freePtr = *ptr;
719 *ptr = freePtr->next;
721 destroy_cursor( freePtr->hIcon );
722 HeapFree( GetProcessHeap(), 0, freePtr );
723 continue;
725 ptr = &(*ptr)->next;
728 LeaveCriticalSection( &IconCrst );
732 * The following macro functions account for the irregularities of
733 * accessing cursor and icon resources in files and resource entries.
735 typedef BOOL (*fnGetCIEntry)( LPVOID dir, int n,
736 int *width, int *height, int *bits );
738 /**********************************************************************
739 * CURSORICON_FindBestIcon
741 * Find the icon closest to the requested size and number of colors.
743 static int CURSORICON_FindBestIcon( LPVOID dir, fnGetCIEntry get_entry,
744 int width, int height, int colors )
746 int i, cx, cy, bits, bestEntry = -1;
747 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
748 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
750 /* Find Best Fit */
751 iTotalDiff = 0xFFFFFFFF;
752 iColorDiff = 0xFFFFFFFF;
753 for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
755 iTempXDiff = abs(width - cx);
756 iTempYDiff = abs(height - cy);
758 if(iTotalDiff > (iTempXDiff + iTempYDiff))
760 iXDiff = iTempXDiff;
761 iYDiff = iTempYDiff;
762 iTotalDiff = iXDiff + iYDiff;
766 /* Find Best Colors for Best Fit */
767 for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
769 if(abs(width - cx) == iXDiff && abs(height - cy) == iYDiff)
771 iTempColorDiff = abs(colors - (1<<bits));
772 if(iColorDiff > iTempColorDiff)
774 bestEntry = i;
775 iColorDiff = iTempColorDiff;
780 return bestEntry;
783 static BOOL CURSORICON_GetResIconEntry( LPVOID dir, int n,
784 int *width, int *height, int *bits )
786 CURSORICONDIR *resdir = dir;
787 ICONRESDIR *icon;
789 if ( resdir->idCount <= n )
790 return FALSE;
791 icon = &resdir->idEntries[n].ResInfo.icon;
792 *width = icon->bWidth;
793 *height = icon->bHeight;
794 *bits = resdir->idEntries[n].wBitCount;
795 return TRUE;
798 /**********************************************************************
799 * CURSORICON_FindBestCursor
801 * Find the cursor closest to the requested size.
802 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
803 * ignored too
805 static int CURSORICON_FindBestCursor( LPVOID dir, fnGetCIEntry get_entry,
806 int width, int height, int color )
808 int i, maxwidth, maxheight, cx, cy, bits, bestEntry = -1;
810 /* Double height to account for AND and XOR masks */
812 height *= 2;
814 /* First find the largest one smaller than or equal to the requested size*/
816 maxwidth = maxheight = 0;
817 for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
819 if ((cx <= width) && (cy <= height) &&
820 (cx > maxwidth) && (cy > maxheight) &&
821 (bits == 1))
823 bestEntry = i;
824 maxwidth = cx;
825 maxheight = cy;
828 if (bestEntry != -1) return bestEntry;
830 /* Now find the smallest one larger than the requested size */
832 maxwidth = maxheight = 255;
833 for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
835 if (((cx < maxwidth) && (cy < maxheight) && (bits == 1)) ||
836 (bestEntry==-1))
838 bestEntry = i;
839 maxwidth = cx;
840 maxheight = cy;
844 return bestEntry;
847 static BOOL CURSORICON_GetResCursorEntry( LPVOID dir, int n,
848 int *width, int *height, int *bits )
850 CURSORICONDIR *resdir = dir;
851 CURSORDIR *cursor;
853 if ( resdir->idCount <= n )
854 return FALSE;
855 cursor = &resdir->idEntries[n].ResInfo.cursor;
856 *width = cursor->wWidth;
857 *height = cursor->wHeight;
858 *bits = resdir->idEntries[n].wBitCount;
859 return TRUE;
862 static CURSORICONDIRENTRY *CURSORICON_FindBestIconRes( CURSORICONDIR * dir,
863 int width, int height, int colors )
865 int n;
867 n = CURSORICON_FindBestIcon( dir, CURSORICON_GetResIconEntry,
868 width, height, colors );
869 if ( n < 0 )
870 return NULL;
871 return &dir->idEntries[n];
874 static CURSORICONDIRENTRY *CURSORICON_FindBestCursorRes( CURSORICONDIR *dir,
875 int width, int height, int color )
877 int n = CURSORICON_FindBestCursor( dir, CURSORICON_GetResCursorEntry,
878 width, height, color );
879 if ( n < 0 )
880 return NULL;
881 return &dir->idEntries[n];
884 static BOOL CURSORICON_GetFileEntry( LPVOID dir, int n,
885 int *width, int *height, int *bits )
887 CURSORICONFILEDIR *filedir = dir;
888 CURSORICONFILEDIRENTRY *entry;
890 if ( filedir->idCount <= n )
891 return FALSE;
892 entry = &filedir->idEntries[n];
893 *width = entry->bWidth;
894 *height = entry->bHeight;
895 *bits = entry->bColorCount;
896 return TRUE;
899 static CURSORICONFILEDIRENTRY *CURSORICON_FindBestCursorFile( CURSORICONFILEDIR *dir,
900 int width, int height, int color )
902 int n = CURSORICON_FindBestCursor( dir, CURSORICON_GetFileEntry,
903 width, height, color );
904 if ( n < 0 )
905 return NULL;
906 return &dir->idEntries[n];
909 static CURSORICONFILEDIRENTRY *CURSORICON_FindBestIconFile( CURSORICONFILEDIR *dir,
910 int width, int height, int color )
912 int n = CURSORICON_FindBestIcon( dir, CURSORICON_GetFileEntry,
913 width, height, color );
914 if ( n < 0 )
915 return NULL;
916 return &dir->idEntries[n];
919 static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
920 POINT16 hotspot, BOOL bIcon,
921 DWORD dwVersion,
922 INT width, INT height,
923 UINT cFlag )
925 HCURSOR cursor;
926 cursor_frame_t frame = {0};
927 static HDC hdcMem;
928 int sizeAnd, sizeXor;
929 HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
930 BITMAP bmpXor, bmpAnd;
931 BOOL DoStretch;
932 INT size;
934 if (dwVersion == 0x00020000)
936 FIXME_(cursor)("\t2.xx resources are not supported\n");
937 return 0;
940 /* Check bitmap header */
942 if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
943 (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) ||
944 bmi->bmiHeader.biCompression != BI_RGB) )
946 WARN_(cursor)("\tinvalid resource bitmap header.\n");
947 return 0;
950 size = bitmap_info_size( bmi, DIB_RGB_COLORS );
952 if (!width) width = bmi->bmiHeader.biWidth;
953 if (!height) height = bmi->bmiHeader.biHeight/2;
954 DoStretch = (bmi->bmiHeader.biHeight/2 != height) ||
955 (bmi->bmiHeader.biWidth != width);
957 if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
958 if (screen_dc)
960 BITMAPINFO* pInfo;
962 /* Make sure we have room for the monochrome bitmap later on.
963 * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
964 * up to and including the biBitCount. In-memory icon resource
965 * format is as follows:
967 * BITMAPINFOHEADER icHeader // DIB header
968 * RGBQUAD icColors[] // Color table
969 * BYTE icXOR[] // DIB bits for XOR mask
970 * BYTE icAND[] // DIB bits for AND mask
973 if ((pInfo = HeapAlloc( GetProcessHeap(), 0,
974 max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))))
976 memcpy( pInfo, bmi, size );
977 pInfo->bmiHeader.biHeight /= 2;
979 /* Create the XOR bitmap */
981 if (DoStretch) {
982 if(bIcon)
984 hXorBits = CreateCompatibleBitmap(screen_dc, width, height);
986 else
988 hXorBits = CreateBitmap(width, height, 1, 1, NULL);
990 if(hXorBits)
992 HBITMAP hOld;
993 BOOL res = FALSE;
995 if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
996 if (hdcMem) {
997 hOld = SelectObject(hdcMem, hXorBits);
998 res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
999 bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2,
1000 (char*)bmi + size, pInfo, DIB_RGB_COLORS, SRCCOPY);
1001 SelectObject(hdcMem, hOld);
1003 if (!res) { DeleteObject(hXorBits); hXorBits = 0; }
1005 } else {
1006 if (is_dib_monochrome(bmi)) {
1007 hXorBits = CreateBitmap(width, height, 1, 1, NULL);
1008 SetDIBits(screen_dc, hXorBits, 0, height,
1009 (char*)bmi + size, pInfo, DIB_RGB_COLORS);
1011 else
1012 hXorBits = CreateDIBitmap(screen_dc, &pInfo->bmiHeader,
1013 CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS);
1016 if( hXorBits )
1018 char* xbits = (char *)bmi + size +
1019 get_dib_width_bytes( bmi->bmiHeader.biWidth,
1020 bmi->bmiHeader.biBitCount ) * abs( bmi->bmiHeader.biHeight ) / 2;
1022 pInfo->bmiHeader.biBitCount = 1;
1023 if (pInfo->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
1025 RGBQUAD *rgb = pInfo->bmiColors;
1027 pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
1028 rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
1029 rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
1030 rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
1032 else
1034 RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
1036 rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
1037 rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
1040 /* Create the AND bitmap */
1042 if (DoStretch) {
1043 if ((hAndBits = CreateBitmap(width, height, 1, 1, NULL))) {
1044 HBITMAP hOld;
1045 BOOL res = FALSE;
1047 if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
1048 if (hdcMem) {
1049 hOld = SelectObject(hdcMem, hAndBits);
1050 res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
1051 pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight,
1052 xbits, pInfo, DIB_RGB_COLORS, SRCCOPY);
1053 SelectObject(hdcMem, hOld);
1055 if (!res) { DeleteObject(hAndBits); hAndBits = 0; }
1057 } else {
1058 hAndBits = CreateBitmap(width, height, 1, 1, NULL);
1060 if (hAndBits) SetDIBits(screen_dc, hAndBits, 0, height,
1061 xbits, pInfo, DIB_RGB_COLORS);
1064 if( !hAndBits ) DeleteObject( hXorBits );
1066 HeapFree( GetProcessHeap(), 0, pInfo );
1070 if( !hXorBits || !hAndBits )
1072 WARN_(cursor)("\tunable to create an icon bitmap.\n");
1073 return 0;
1076 /* Setup a cursor frame, send it to the server */
1077 GetObjectA( hXorBits, sizeof(bmpXor), &bmpXor );
1078 GetObjectA( hAndBits, sizeof(bmpAnd), &bmpAnd );
1079 sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
1080 sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
1082 cursor = create_cursor( 1, 0 );
1083 frame.xhot = hotspot.x;
1084 frame.yhot = hotspot.y;
1085 frame.width = bmpXor.bmWidth;
1086 frame.height = bmpXor.bmHeight;
1087 frame.and_width_bytes = bmpAnd.bmWidthBytes;
1088 frame.xor_width_bytes = bmpXor.bmWidthBytes;
1089 frame.planes = bmpXor.bmPlanes;
1090 frame.bpp = bmpXor.bmBitsPixel;
1091 frame.bits = HeapAlloc( GetProcessHeap(), 0, sizeAnd + sizeXor );
1092 GetBitmapBits( hAndBits, sizeAnd, frame.bits );
1093 GetBitmapBits( hXorBits, sizeXor, frame.bits + sizeAnd );
1094 set_cursor_frame( cursor, 0, &frame );
1095 HeapFree( GetProcessHeap(), 0, frame.bits );
1097 DeleteObject( hAndBits );
1098 DeleteObject( hXorBits );
1103 /**********************************************************************
1104 * .ANI cursor support
1106 #define RIFF_FOURCC( c0, c1, c2, c3 ) \
1107 ( (DWORD)(BYTE)(c0) | ( (DWORD)(BYTE)(c1) << 8 ) | \
1108 ( (DWORD)(BYTE)(c2) << 16 ) | ( (DWORD)(BYTE)(c3) << 24 ) )
1110 #define ANI_RIFF_ID RIFF_FOURCC('R', 'I', 'F', 'F')
1111 #define ANI_LIST_ID RIFF_FOURCC('L', 'I', 'S', 'T')
1112 #define ANI_ACON_ID RIFF_FOURCC('A', 'C', 'O', 'N')
1113 #define ANI_anih_ID RIFF_FOURCC('a', 'n', 'i', 'h')
1114 #define ANI_seq__ID RIFF_FOURCC('s', 'e', 'q', ' ')
1115 #define ANI_fram_ID RIFF_FOURCC('f', 'r', 'a', 'm')
1117 #define ANI_FLAG_ICON 0x1
1118 #define ANI_FLAG_SEQUENCE 0x2
1120 typedef struct {
1121 DWORD header_size;
1122 DWORD num_frames;
1123 DWORD num_steps;
1124 DWORD width;
1125 DWORD height;
1126 DWORD bpp;
1127 DWORD num_planes;
1128 DWORD display_rate;
1129 DWORD flags;
1130 } ani_header;
1132 typedef struct {
1133 DWORD data_size;
1134 const unsigned char *data;
1135 } riff_chunk_t;
1137 static void dump_ani_header( const ani_header *header )
1139 TRACE(" header size: %d\n", header->header_size);
1140 TRACE(" frames: %d\n", header->num_frames);
1141 TRACE(" steps: %d\n", header->num_steps);
1142 TRACE(" width: %d\n", header->width);
1143 TRACE(" height: %d\n", header->height);
1144 TRACE(" bpp: %d\n", header->bpp);
1145 TRACE(" planes: %d\n", header->num_planes);
1146 TRACE(" display rate: %d\n", header->display_rate);
1147 TRACE(" flags: 0x%08x\n", header->flags);
1152 * RIFF:
1153 * DWORD "RIFF"
1154 * DWORD size
1155 * DWORD riff_id
1156 * BYTE[] data
1158 * LIST:
1159 * DWORD "LIST"
1160 * DWORD size
1161 * DWORD list_id
1162 * BYTE[] data
1164 * CHUNK:
1165 * DWORD chunk_id
1166 * DWORD size
1167 * BYTE[] data
1169 static void riff_find_chunk( DWORD chunk_id, DWORD chunk_type, const riff_chunk_t *parent_chunk, riff_chunk_t *chunk )
1171 const unsigned char *ptr = parent_chunk->data;
1172 const unsigned char *end = parent_chunk->data + (parent_chunk->data_size - (2 * sizeof(DWORD)));
1174 if (chunk_type == ANI_LIST_ID || chunk_type == ANI_RIFF_ID) end -= sizeof(DWORD);
1176 while (ptr < end)
1178 if ((!chunk_type && *(DWORD *)ptr == chunk_id )
1179 || (chunk_type && *(DWORD *)ptr == chunk_type && *((DWORD *)ptr + 2) == chunk_id ))
1181 ptr += sizeof(DWORD);
1182 chunk->data_size = *(DWORD *)ptr;
1183 ptr += sizeof(DWORD);
1184 if (chunk_type == ANI_LIST_ID || chunk_type == ANI_RIFF_ID) ptr += sizeof(DWORD);
1185 chunk->data = ptr;
1187 return;
1190 ptr += sizeof(DWORD);
1191 ptr += *(DWORD *)ptr;
1192 ptr += sizeof(DWORD);
1198 * .ANI layout:
1200 * RIFF:'ACON' RIFF chunk
1201 * |- CHUNK:'anih' Header
1202 * |- CHUNK:'seq ' Sequence information (optional)
1203 * \- LIST:'fram' Frame list
1204 * |- CHUNK:icon Cursor frames
1205 * |- CHUNK:icon
1206 * |- ...
1207 * \- CHUNK:icon
1209 static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
1210 INT width, INT height )
1212 HCURSOR cursor;
1213 ani_header header = {0};
1214 LPBYTE frame_bits = 0;
1215 POINT16 hotspot;
1216 CURSORICONFILEDIRENTRY *entry;
1218 riff_chunk_t root_chunk = { bits_size, bits };
1219 riff_chunk_t ACON_chunk = {0};
1220 riff_chunk_t anih_chunk = {0};
1221 riff_chunk_t fram_chunk = {0};
1222 const unsigned char *icon_data;
1224 TRACE("bits %p, bits_size %d\n", bits, bits_size);
1226 if (!bits) return 0;
1228 riff_find_chunk( ANI_ACON_ID, ANI_RIFF_ID, &root_chunk, &ACON_chunk );
1229 if (!ACON_chunk.data)
1231 ERR("Failed to get root chunk.\n");
1232 return 0;
1235 riff_find_chunk( ANI_anih_ID, 0, &ACON_chunk, &anih_chunk );
1236 if (!anih_chunk.data)
1238 ERR("Failed to get 'anih' chunk.\n");
1239 return 0;
1241 memcpy( &header, anih_chunk.data, sizeof(header) );
1242 dump_ani_header( &header );
1244 riff_find_chunk( ANI_fram_ID, ANI_LIST_ID, &ACON_chunk, &fram_chunk );
1245 if (!fram_chunk.data)
1247 ERR("Failed to get icon list.\n");
1248 return 0;
1251 /* FIXME: For now, just load the first frame. Before we can load all the
1252 * frames, we need to write the needed code in wineserver, etc. to handle
1253 * cursors. Once this code is written, we can extend it to support .ani
1254 * cursors and then update user32 and winex11.drv to load all frames.
1256 * Hopefully this will at least make some games (C&C3, etc.) more playable
1257 * in the mean time.
1259 FIXME("Loading all frames for .ani cursors not implemented.\n");
1260 icon_data = fram_chunk.data + (2 * sizeof(DWORD));
1262 entry = CURSORICON_FindBestCursorFile( (CURSORICONFILEDIR *) icon_data,
1263 width, height, 1 );
1265 frame_bits = HeapAlloc( GetProcessHeap(), 0, entry->dwDIBSize );
1266 memcpy( frame_bits, icon_data + entry->dwDIBOffset, entry->dwDIBSize );
1268 if (!header.width || !header.height)
1270 header.width = entry->bWidth;
1271 header.height = entry->bHeight;
1274 hotspot.x = entry->xHotspot;
1275 hotspot.y = entry->yHotspot;
1277 cursor = CURSORICON_CreateIconFromBMI( (BITMAPINFO *) frame_bits, hotspot,
1278 FALSE, 0x00030000, header.width, header.height, 0 );
1280 HeapFree( GetProcessHeap(), 0, frame_bits );
1282 return cursor;
1286 /**********************************************************************
1287 * CreateIconFromResourceEx (USER32.@)
1289 * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
1290 * with cbSize parameter as well.
1292 HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
1293 BOOL bIcon, DWORD dwVersion,
1294 INT width, INT height,
1295 UINT cFlag )
1297 POINT16 hotspot;
1298 BITMAPINFO *bmi;
1300 hotspot.x = ICON_HOTSPOT;
1301 hotspot.y = ICON_HOTSPOT;
1303 TRACE_(cursor)("%p (%u bytes), ver %08x, %ix%i %s %s\n",
1304 bits, cbSize, dwVersion, width, height,
1305 bIcon ? "icon" : "cursor", (cFlag & LR_MONOCHROME) ? "mono" : "" );
1307 if (bIcon)
1308 bmi = (BITMAPINFO *)bits;
1309 else /* get the hotspot */
1311 POINT16 *pt = (POINT16 *)bits;
1312 hotspot = *pt;
1313 bmi = (BITMAPINFO *)(pt + 1);
1316 return CURSORICON_CreateIconFromBMI( bmi, hotspot, bIcon, dwVersion,
1317 width, height, cFlag );
1321 /**********************************************************************
1322 * CreateIconFromResource (USER32.@)
1324 HICON WINAPI CreateIconFromResource( LPBYTE bits, UINT cbSize,
1325 BOOL bIcon, DWORD dwVersion)
1327 return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
1331 static HICON CURSORICON_LoadFromFile( LPCWSTR filename,
1332 INT width, INT height, INT colors,
1333 BOOL fCursor, UINT loadflags)
1335 CURSORICONFILEDIRENTRY *entry;
1336 CURSORICONFILEDIR *dir;
1337 DWORD filesize = 0;
1338 HICON hIcon = 0;
1339 LPBYTE bits;
1340 POINT16 hotspot;
1342 TRACE("loading %s\n", debugstr_w( filename ));
1344 bits = map_fileW( filename, &filesize );
1345 if (!bits)
1346 return hIcon;
1348 /* Check for .ani. */
1349 if (memcmp( bits, "RIFF", 4 ) == 0)
1351 hIcon = CURSORICON_CreateIconFromANI( bits, filesize, width, height );
1352 goto end;
1355 dir = (CURSORICONFILEDIR*) bits;
1356 if ( filesize < sizeof(*dir) )
1357 goto end;
1359 if ( filesize < (sizeof(*dir) + sizeof(dir->idEntries[0])*(dir->idCount-1)) )
1360 goto end;
1362 if ( fCursor )
1363 entry = CURSORICON_FindBestCursorFile( dir, width, height, colors );
1364 else
1365 entry = CURSORICON_FindBestIconFile( dir, width, height, colors );
1367 if ( !entry )
1368 goto end;
1370 /* check that we don't run off the end of the file */
1371 if ( entry->dwDIBOffset > filesize )
1372 goto end;
1373 if ( entry->dwDIBOffset + entry->dwDIBSize > filesize )
1374 goto end;
1376 hotspot.x = entry->xHotspot;
1377 hotspot.y = entry->yHotspot;
1378 hIcon = CURSORICON_CreateIconFromBMI( (BITMAPINFO *)&bits[entry->dwDIBOffset],
1379 hotspot, !fCursor, 0x00030000,
1380 width, height, loadflags );
1381 end:
1382 TRACE("loaded %s -> %p\n", debugstr_w( filename ), hIcon );
1383 UnmapViewOfFile( bits );
1384 return hIcon;
1387 /**********************************************************************
1388 * CURSORICON_Load
1390 * Load a cursor or icon from resource or file.
1392 static HICON CURSORICON_Load(HINSTANCE hInstance, LPCWSTR name,
1393 INT width, INT height, INT colors,
1394 BOOL fCursor, UINT loadflags)
1396 HANDLE handle = 0;
1397 HICON hIcon = 0;
1398 HRSRC hRsrc, hGroupRsrc;
1399 CURSORICONDIR *dir;
1400 CURSORICONDIRENTRY *dirEntry;
1401 LPBYTE bits;
1402 WORD wResId;
1403 DWORD dwBytesInRes;
1405 TRACE("%p, %s, %dx%d, colors %d, fCursor %d, flags 0x%04x\n",
1406 hInstance, debugstr_w(name), width, height, colors, fCursor, loadflags);
1408 if ( loadflags & LR_LOADFROMFILE ) /* Load from file */
1409 return CURSORICON_LoadFromFile( name, width, height, colors, fCursor, loadflags );
1411 if (!hInstance) hInstance = user32_module; /* Load OEM cursor/icon */
1413 /* Normalize hInstance (must be uniquely represented for icon cache) */
1415 if (!HIWORD( hInstance ))
1416 hInstance = HINSTANCE_32(GetExePtr( HINSTANCE_16(hInstance) ));
1418 /* Get directory resource ID */
1420 if (!(hRsrc = FindResourceW( hInstance, name,
1421 (LPWSTR)(fCursor ? RT_GROUP_CURSOR : RT_GROUP_ICON) )))
1422 return 0;
1423 hGroupRsrc = hRsrc;
1425 /* Find the best entry in the directory */
1427 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
1428 if (!(dir = LockResource( handle ))) return 0;
1429 if (fCursor)
1430 dirEntry = CURSORICON_FindBestCursorRes( dir, width, height, 1);
1431 else
1432 dirEntry = CURSORICON_FindBestIconRes( dir, width, height, colors );
1433 if (!dirEntry) return 0;
1434 wResId = dirEntry->wResId;
1435 dwBytesInRes = dirEntry->dwBytesInRes;
1436 FreeResource( handle );
1438 /* Load the resource */
1440 if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
1441 (LPWSTR)(fCursor ? RT_CURSOR : RT_ICON) ))) return 0;
1443 /* If shared icon, check whether it was already loaded */
1444 if ( (loadflags & LR_SHARED)
1445 && (hIcon = CURSORICON_FindSharedIcon( hInstance, hRsrc ) ) != 0 )
1446 return hIcon;
1448 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
1449 bits = LockResource( handle );
1450 hIcon = CreateIconFromResourceEx( bits, dwBytesInRes,
1451 !fCursor, 0x00030000, width, height, loadflags);
1452 FreeResource( handle );
1454 /* If shared icon, add to icon cache */
1456 if ( hIcon && (loadflags & LR_SHARED) )
1457 CURSORICON_AddSharedIcon( hInstance, hRsrc, hGroupRsrc, hIcon );
1459 return hIcon;
1462 /***********************************************************************
1463 * CURSORICON_Copy
1465 * Make a copy of a cursor or icon.
1467 static HICON CURSORICON_Copy( HINSTANCE16 hInst16, HICON hIcon )
1469 /* Should animated cursors be copyable like this as well? */
1470 HCURSOR new_cursor;
1471 cursor_frame_t frame;
1473 if (!hIcon || !get_cursor_frame( hIcon, 0, &frame ))
1475 return 0;
1478 new_cursor = create_cursor( 1, 0 );
1479 set_cursor_frame( new_cursor, 0, &frame );
1480 HeapFree( GetProcessHeap(), 0, frame.bits );
1482 return new_cursor;
1485 /*************************************************************************
1486 * CURSORICON_ExtCopy
1488 * Copies an Image from the Cache if LR_COPYFROMRESOURCE is specified
1490 * PARAMS
1491 * Handle [I] handle to an Image
1492 * nType [I] Type of Handle (IMAGE_CURSOR | IMAGE_ICON)
1493 * iDesiredCX [I] The Desired width of the Image
1494 * iDesiredCY [I] The desired height of the Image
1495 * nFlags [I] The flags from CopyImage
1497 * RETURNS
1498 * Success: The new handle of the Image
1500 * NOTES
1501 * LR_COPYDELETEORG and LR_MONOCHROME are currently not implemented.
1502 * LR_MONOCHROME should be implemented by CreateIconFromResourceEx.
1503 * LR_COPYFROMRESOURCE will only work if the Image is in the Cache.
1508 static HICON CURSORICON_ExtCopy(HICON hIcon, UINT nType,
1509 INT iDesiredCX, INT iDesiredCY,
1510 UINT nFlags)
1512 HICON hNew=0;
1514 TRACE_(icon)("hIcon %p, nType %u, iDesiredCX %i, iDesiredCY %i, nFlags %u\n",
1515 hIcon, nType, iDesiredCX, iDesiredCY, nFlags);
1517 if(hIcon == 0)
1519 return 0;
1522 /* Best Fit or Monochrome */
1523 if( (nFlags & LR_COPYFROMRESOURCE
1524 && (iDesiredCX > 0 || iDesiredCY > 0))
1525 || nFlags & LR_MONOCHROME)
1527 ICONCACHE* pIconCache = CURSORICON_FindCache(hIcon);
1529 /* Not Found in Cache, then do a straight copy
1531 if(pIconCache == NULL)
1533 hNew = CURSORICON_Copy(0, hIcon);
1534 if(nFlags & LR_COPYFROMRESOURCE)
1536 TRACE_(icon)("LR_COPYFROMRESOURCE: Failed to load from cache\n");
1539 else
1541 int iTargetCY = iDesiredCY, iTargetCX = iDesiredCX;
1542 LPBYTE pBits;
1543 HANDLE hMem;
1544 HRSRC hRsrc;
1545 DWORD dwBytesInRes;
1546 WORD wResId;
1547 CURSORICONDIR *pDir;
1548 CURSORICONDIRENTRY *pDirEntry;
1549 BOOL bIsIcon = (nType == IMAGE_ICON);
1551 /* Completing iDesiredCX CY for Monochrome Bitmaps if needed
1553 if(((nFlags & LR_MONOCHROME) && !(nFlags & LR_COPYFROMRESOURCE))
1554 || (iDesiredCX == 0 && iDesiredCY == 0))
1556 iDesiredCY = GetSystemMetrics(bIsIcon ?
1557 SM_CYICON : SM_CYCURSOR);
1558 iDesiredCX = GetSystemMetrics(bIsIcon ?
1559 SM_CXICON : SM_CXCURSOR);
1562 /* Retrieve the CURSORICONDIRENTRY
1564 if (!(hMem = LoadResource( pIconCache->hModule ,
1565 pIconCache->hGroupRsrc)))
1567 return 0;
1569 if (!(pDir = LockResource( hMem )))
1571 return 0;
1574 /* Find Best Fit
1576 if(bIsIcon)
1578 pDirEntry = CURSORICON_FindBestIconRes(
1579 pDir, iDesiredCX, iDesiredCY, 256 );
1581 else
1583 pDirEntry = CURSORICON_FindBestCursorRes(
1584 pDir, iDesiredCX, iDesiredCY, 1);
1587 wResId = pDirEntry->wResId;
1588 dwBytesInRes = pDirEntry->dwBytesInRes;
1589 FreeResource(hMem);
1591 TRACE_(icon)("ResID %u, BytesInRes %u, Width %d, Height %d DX %d, DY %d\n",
1592 wResId, dwBytesInRes, pDirEntry->ResInfo.icon.bWidth,
1593 pDirEntry->ResInfo.icon.bHeight, iDesiredCX, iDesiredCY);
1595 /* Get the Best Fit
1597 if (!(hRsrc = FindResourceW(pIconCache->hModule ,
1598 MAKEINTRESOURCEW(wResId), (LPWSTR)(bIsIcon ? RT_ICON : RT_CURSOR))))
1600 return 0;
1602 if (!(hMem = LoadResource( pIconCache->hModule , hRsrc )))
1604 return 0;
1607 pBits = LockResource( hMem );
1609 if(nFlags & LR_DEFAULTSIZE)
1611 iTargetCY = GetSystemMetrics(SM_CYICON);
1612 iTargetCX = GetSystemMetrics(SM_CXICON);
1615 /* Create a New Icon with the proper dimension
1617 hNew = CreateIconFromResourceEx( pBits, dwBytesInRes,
1618 bIsIcon, 0x00030000, iTargetCX, iTargetCY, nFlags);
1619 FreeResource(hMem);
1622 else hNew = CURSORICON_Copy(0, hIcon);
1623 return hNew;
1627 /***********************************************************************
1628 * CreateCursor (USER32.@)
1630 HCURSOR WINAPI CreateCursor( HINSTANCE hInstance,
1631 INT xHotSpot, INT yHotSpot,
1632 INT nWidth, INT nHeight,
1633 LPCVOID lpANDbits, LPCVOID lpXORbits )
1635 CURSORICONINFO info;
1637 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1638 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1640 info.ptHotSpot.x = xHotSpot;
1641 info.ptHotSpot.y = yHotSpot;
1642 info.nWidth = nWidth;
1643 info.nHeight = nHeight;
1644 info.nWidthBytes = 0;
1645 info.bPlanes = 1;
1646 info.bBitsPerPixel = 1;
1648 return HICON_32(CreateCursorIconIndirect16(0, &info, lpANDbits, lpXORbits));
1652 /***********************************************************************
1653 * CreateIcon (USER.407)
1655 HICON16 WINAPI CreateIcon16( HINSTANCE16 hInstance, INT16 nWidth,
1656 INT16 nHeight, BYTE bPlanes, BYTE bBitsPixel,
1657 LPCVOID lpANDbits, LPCVOID lpXORbits )
1659 CURSORICONINFO info;
1661 TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1662 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1664 info.ptHotSpot.x = ICON_HOTSPOT;
1665 info.ptHotSpot.y = ICON_HOTSPOT;
1666 info.nWidth = nWidth;
1667 info.nHeight = nHeight;
1668 info.nWidthBytes = 0;
1669 info.bPlanes = bPlanes;
1670 info.bBitsPerPixel = bBitsPixel;
1672 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1676 /***********************************************************************
1677 * CreateIcon (USER32.@)
1679 * Creates an icon based on the specified bitmaps. The bitmaps must be
1680 * provided in a device dependent format and will be resized to
1681 * (SM_CXICON,SM_CYICON) and depth converted to match the screen's color
1682 * depth. The provided bitmaps must be top-down bitmaps.
1683 * Although Windows does not support 15bpp(*) this API must support it
1684 * for Winelib applications.
1686 * (*) Windows does not support 15bpp but it supports the 555 RGB 16bpp
1687 * format!
1689 * RETURNS
1690 * Success: handle to an icon
1691 * Failure: NULL
1693 * FIXME: Do we need to resize the bitmaps?
1695 HICON WINAPI CreateIcon(
1696 HINSTANCE hInstance, /* [in] the application's hInstance */
1697 INT nWidth, /* [in] the width of the provided bitmaps */
1698 INT nHeight, /* [in] the height of the provided bitmaps */
1699 BYTE bPlanes, /* [in] the number of planes in the provided bitmaps */
1700 BYTE bBitsPixel, /* [in] the number of bits per pixel of the lpXORbits bitmap */
1701 LPCVOID lpANDbits, /* [in] a monochrome bitmap representing the icon's mask */
1702 LPCVOID lpXORbits) /* [in] the icon's 'color' bitmap */
1704 ICONINFO iinfo;
1705 HICON hIcon;
1707 TRACE_(icon)("%dx%d, planes %d, bpp %d, xor %p, and %p\n",
1708 nWidth, nHeight, bPlanes, bBitsPixel, lpXORbits, lpANDbits);
1710 iinfo.fIcon = TRUE;
1711 iinfo.xHotspot = ICON_HOTSPOT;
1712 iinfo.yHotspot = ICON_HOTSPOT;
1713 iinfo.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpANDbits );
1714 iinfo.hbmColor = CreateBitmap( nWidth, nHeight, bPlanes, bBitsPixel, lpXORbits );
1716 hIcon = CreateIconIndirect( &iinfo );
1718 DeleteObject( iinfo.hbmMask );
1719 DeleteObject( iinfo.hbmColor );
1721 return hIcon;
1725 /***********************************************************************
1726 * CreateCursorIconIndirect (USER.408)
1728 HGLOBAL16 WINAPI CreateCursorIconIndirect16( HINSTANCE16 hInstance,
1729 CURSORICONINFO *info,
1730 LPCVOID lpANDbits,
1731 LPCVOID lpXORbits )
1733 HCURSOR cursor;
1734 cursor_frame_t frame;
1735 int sizeAnd, sizeXor;
1737 if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
1738 info->nWidthBytes = get_bitmap_width_bytes(info->nWidth,info->bBitsPerPixel);
1739 sizeXor = info->nHeight * info->nWidthBytes;
1740 sizeAnd = info->nHeight * get_bitmap_width_bytes( info->nWidth, 1 );
1742 cursor = create_cursor( 1, 0 );
1743 frame.xhot = info->ptHotSpot.x;
1744 frame.yhot = info->ptHotSpot.y;
1745 frame.width = info->nWidth;
1746 frame.height = info->nHeight;
1747 frame.and_width_bytes = get_bitmap_width_bytes( info->nWidth, 1 );
1748 frame.xor_width_bytes = info->nWidthBytes;
1749 frame.planes = info->bPlanes;
1750 frame.bpp = info->bBitsPerPixel;
1751 frame.bits = HeapAlloc( GetProcessHeap(), 0, sizeAnd + sizeXor );
1752 CopyMemory( frame.bits, lpANDbits, sizeAnd );
1753 CopyMemory( frame.bits + sizeAnd, lpXORbits, sizeXor );
1754 set_cursor_frame( cursor, 0, &frame );
1755 HeapFree( GetProcessHeap(), 0, frame.bits );
1757 return HICON_16(cursor);
1761 /***********************************************************************
1762 * CopyIcon (USER.368)
1764 HICON16 WINAPI CopyIcon16( HINSTANCE16 hInstance, HICON16 hIcon )
1766 TRACE_(icon)("%04x %04x\n", hInstance, hIcon );
1767 return HICON_16(CURSORICON_Copy(hInstance, HICON_32(hIcon)));
1771 /***********************************************************************
1772 * CopyIcon (USER32.@)
1774 HICON WINAPI CopyIcon( HICON hIcon )
1776 TRACE_(icon)("%p\n", hIcon );
1777 return CURSORICON_Copy( 0, hIcon );
1781 /***********************************************************************
1782 * CopyCursor (USER.369)
1784 HCURSOR16 WINAPI CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
1786 TRACE_(cursor)("%04x %04x\n", hInstance, hCursor );
1787 return HICON_16(CURSORICON_Copy(hInstance, HCURSOR_32(hCursor)));
1790 /**********************************************************************
1791 * DestroyIcon32 (USER.610)
1793 * This routine is actually exported from Win95 USER under the name
1794 * DestroyIcon32 ... The behaviour implemented here should mimic
1795 * the Win95 one exactly, especially the return values, which
1796 * depend on the setting of various flags.
1798 WORD WINAPI DestroyIcon32( HGLOBAL16 handle, UINT16 flags )
1800 WORD retv;
1802 TRACE_(icon)("(%04x, %04x)\n", handle, flags );
1804 /* Check whether destroying active cursor */
1806 if ( get_user_thread_info()->cursor == HICON_32(handle) )
1808 WARN_(cursor)("Destroying active cursor!\n" );
1809 return FALSE;
1812 /* Try shared cursor/icon first */
1814 if ( !(flags & CID_NONSHARED) )
1816 INT count = CURSORICON_DelSharedIcon(HICON_32(handle));
1818 if ( count != -1 )
1819 return (flags & CID_WIN32)? TRUE : (count == 0);
1821 /* FIXME: OEM cursors/icons should be recognized */
1824 /* Now assume non-shared cursor/icon */
1826 retv = destroy_cursor( HCURSOR_32(handle) );
1827 return (flags & CID_RESOURCE)? retv : TRUE;
1830 /***********************************************************************
1831 * DestroyIcon (USER32.@)
1833 BOOL WINAPI DestroyIcon( HICON hIcon )
1835 return DestroyIcon32(HICON_16(hIcon), CID_WIN32);
1839 /***********************************************************************
1840 * DestroyCursor (USER32.@)
1842 BOOL WINAPI DestroyCursor( HCURSOR hCursor )
1844 return DestroyIcon32(HCURSOR_16(hCursor), CID_WIN32);
1848 /***********************************************************************
1849 * DrawIcon (USER32.@)
1851 BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
1853 CURSORICONINFO *ptr;
1854 HDC hMemDC;
1855 HBITMAP hXorBits, hAndBits;
1856 COLORREF oldFg, oldBg;
1858 TRACE("%p, (%d,%d), %p\n", hdc, x, y, hIcon);
1860 if (!(ptr = GlobalLock16(HICON_16(hIcon)))) return FALSE;
1861 if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
1862 hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1,
1863 (char *)(ptr+1) );
1864 hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
1865 ptr->bBitsPerPixel, (char *)(ptr + 1)
1866 + ptr->nHeight * get_bitmap_width_bytes(ptr->nWidth,1) );
1867 oldFg = SetTextColor( hdc, RGB(0,0,0) );
1868 oldBg = SetBkColor( hdc, RGB(255,255,255) );
1870 if (hXorBits && hAndBits)
1872 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1873 BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
1874 SelectObject( hMemDC, hXorBits );
1875 BitBlt(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
1876 SelectObject( hMemDC, hBitTemp );
1878 DeleteDC( hMemDC );
1879 if (hXorBits) DeleteObject( hXorBits );
1880 if (hAndBits) DeleteObject( hAndBits );
1881 GlobalUnlock16(HICON_16(hIcon));
1882 SetTextColor( hdc, oldFg );
1883 SetBkColor( hdc, oldBg );
1884 return TRUE;
1887 /***********************************************************************
1888 * DumpIcon (USER.459)
1890 DWORD WINAPI DumpIcon16( SEGPTR pInfo, WORD *lpLen,
1891 SEGPTR *lpXorBits, SEGPTR *lpAndBits )
1893 CURSORICONINFO *info = MapSL( pInfo );
1894 int sizeAnd, sizeXor;
1896 if (!info) return 0;
1897 sizeXor = info->nHeight * info->nWidthBytes;
1898 sizeAnd = info->nHeight * get_bitmap_width_bytes( info->nWidth, 1 );
1899 if (lpAndBits) *lpAndBits = pInfo + sizeof(CURSORICONINFO);
1900 if (lpXorBits) *lpXorBits = pInfo + sizeof(CURSORICONINFO) + sizeAnd;
1901 if (lpLen) *lpLen = sizeof(CURSORICONINFO) + sizeAnd + sizeXor;
1902 return MAKELONG( sizeXor, sizeXor );
1906 /***********************************************************************
1907 * SetCursor (USER32.@)
1909 * Set the cursor shape.
1911 * RETURNS
1912 * A handle to the previous cursor shape.
1914 HCURSOR WINAPI SetCursor( HCURSOR hCursor /* [in] Handle of cursor to show */ )
1916 struct user_thread_info *thread_info = get_user_thread_info();
1917 HCURSOR hOldCursor;
1919 if (hCursor == thread_info->cursor) return hCursor; /* No change */
1920 TRACE("%p\n", hCursor);
1921 hOldCursor = thread_info->cursor;
1922 thread_info->cursor = hCursor;
1923 /* Change the cursor shape only if it is visible */
1924 if (thread_info->cursor_count >= 0)
1926 USER_Driver->pSetCursor( (CURSORICONINFO*)GlobalLock16(HCURSOR_16(hCursor)) );
1927 GlobalUnlock16(HCURSOR_16(hCursor));
1929 return hOldCursor;
1932 /***********************************************************************
1933 * ShowCursor (USER32.@)
1935 INT WINAPI ShowCursor( BOOL bShow )
1937 struct user_thread_info *thread_info = get_user_thread_info();
1939 TRACE("%d, count=%d\n", bShow, thread_info->cursor_count );
1941 if (bShow)
1943 if (++thread_info->cursor_count == 0) /* Show it */
1945 USER_Driver->pSetCursor((CURSORICONINFO*)GlobalLock16(HCURSOR_16(thread_info->cursor)));
1946 GlobalUnlock16(HCURSOR_16(thread_info->cursor));
1949 else
1951 if (--thread_info->cursor_count == -1) /* Hide it */
1952 USER_Driver->pSetCursor( NULL );
1954 return thread_info->cursor_count;
1957 /***********************************************************************
1958 * GetCursor (USER32.@)
1960 HCURSOR WINAPI GetCursor(void)
1962 return get_user_thread_info()->cursor;
1966 /***********************************************************************
1967 * ClipCursor (USER32.@)
1969 BOOL WINAPI ClipCursor( const RECT *rect )
1971 RECT virt;
1973 SetRect( &virt, 0, 0, GetSystemMetrics( SM_CXVIRTUALSCREEN ),
1974 GetSystemMetrics( SM_CYVIRTUALSCREEN ) );
1975 OffsetRect( &virt, GetSystemMetrics( SM_XVIRTUALSCREEN ),
1976 GetSystemMetrics( SM_YVIRTUALSCREEN ) );
1978 TRACE( "Clipping to: %s was: %s screen: %s\n", wine_dbgstr_rect(rect),
1979 wine_dbgstr_rect(&CURSOR_ClipRect), wine_dbgstr_rect(&virt) );
1981 if (!IntersectRect( &CURSOR_ClipRect, &virt, rect ))
1982 CURSOR_ClipRect = virt;
1984 USER_Driver->pClipCursor( rect );
1985 return TRUE;
1989 /***********************************************************************
1990 * GetClipCursor (USER32.@)
1992 BOOL WINAPI GetClipCursor( RECT *rect )
1994 /* If this is first time - initialize the rect */
1995 if (IsRectEmpty( &CURSOR_ClipRect )) ClipCursor( NULL );
1997 return CopyRect( rect, &CURSOR_ClipRect );
2001 /***********************************************************************
2002 * SetSystemCursor (USER32.@)
2004 BOOL WINAPI SetSystemCursor(HCURSOR hcur, DWORD id)
2006 FIXME("(%p,%08x),stub!\n", hcur, id);
2007 return TRUE;
2011 /**********************************************************************
2012 * LookupIconIdFromDirectoryEx (USER.364)
2014 * FIXME: exact parameter sizes
2016 INT16 WINAPI LookupIconIdFromDirectoryEx16( LPBYTE dir, BOOL16 bIcon,
2017 INT16 width, INT16 height, UINT16 cFlag )
2019 return LookupIconIdFromDirectoryEx( dir, bIcon, width, height, cFlag );
2022 /**********************************************************************
2023 * LookupIconIdFromDirectoryEx (USER32.@)
2025 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE xdir, BOOL bIcon,
2026 INT width, INT height, UINT cFlag )
2028 CURSORICONDIR *dir = (CURSORICONDIR*)xdir;
2029 UINT retVal = 0;
2030 if( dir && !dir->idReserved && (dir->idType & 3) )
2032 CURSORICONDIRENTRY* entry;
2033 HDC hdc;
2034 UINT palEnts;
2035 int colors;
2036 hdc = GetDC(0);
2037 palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
2038 if (palEnts == 0)
2039 palEnts = 256;
2040 colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
2042 ReleaseDC(0, hdc);
2044 if( bIcon )
2045 entry = CURSORICON_FindBestIconRes( dir, width, height, colors );
2046 else
2047 entry = CURSORICON_FindBestCursorRes( dir, width, height, 1);
2049 if( entry ) retVal = entry->wResId;
2051 else WARN_(cursor)("invalid resource directory\n");
2052 return retVal;
2055 /**********************************************************************
2056 * LookupIconIdFromDirectory (USER.?)
2058 INT16 WINAPI LookupIconIdFromDirectory16( LPBYTE dir, BOOL16 bIcon )
2060 return LookupIconIdFromDirectoryEx16( dir, bIcon,
2061 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
2062 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
2065 /**********************************************************************
2066 * LookupIconIdFromDirectory (USER32.@)
2068 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
2070 return LookupIconIdFromDirectoryEx( dir, bIcon,
2071 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
2072 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
2075 /**********************************************************************
2076 * GetIconID (USER.455)
2078 WORD WINAPI GetIconID16( HGLOBAL16 hResource, DWORD resType )
2080 LPBYTE lpDir = GlobalLock16(hResource);
2082 TRACE_(cursor)("hRes=%04x, entries=%i\n",
2083 hResource, lpDir ? ((CURSORICONDIR*)lpDir)->idCount : 0);
2085 switch(resType)
2087 case RT_CURSOR:
2088 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, FALSE,
2089 GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
2090 case RT_ICON:
2091 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, TRUE,
2092 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0 );
2093 default:
2094 WARN_(cursor)("invalid res type %d\n", resType );
2096 return 0;
2099 /**********************************************************************
2100 * LoadCursorIconHandler (USER.336)
2102 * Supposed to load resources of Windows 2.x applications.
2104 HGLOBAL16 WINAPI LoadCursorIconHandler16( HGLOBAL16 hResource, HMODULE16 hModule, HRSRC16 hRsrc )
2106 FIXME_(cursor)("(%04x,%04x,%04x): old 2.x resources are not supported!\n",
2107 hResource, hModule, hRsrc);
2108 return 0;
2111 /**********************************************************************
2112 * LoadIconHandler (USER.456)
2114 HICON16 WINAPI LoadIconHandler16( HGLOBAL16 hResource, BOOL16 bNew )
2116 LPBYTE bits = LockResource16( hResource );
2118 TRACE_(cursor)("hRes=%04x\n",hResource);
2120 return HICON_16(CreateIconFromResourceEx( bits, 0, TRUE,
2121 bNew ? 0x00030000 : 0x00020000, 0, 0, LR_DEFAULTCOLOR));
2124 /***********************************************************************
2125 * LoadCursorW (USER32.@)
2127 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
2129 TRACE("%p, %s\n", hInstance, debugstr_w(name));
2131 return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0,
2132 LR_SHARED | LR_DEFAULTSIZE );
2135 /***********************************************************************
2136 * LoadCursorA (USER32.@)
2138 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
2140 TRACE("%p, %s\n", hInstance, debugstr_a(name));
2142 return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0,
2143 LR_SHARED | LR_DEFAULTSIZE );
2146 /***********************************************************************
2147 * LoadCursorFromFileW (USER32.@)
2149 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
2151 TRACE("%s\n", debugstr_w(name));
2153 return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0,
2154 LR_LOADFROMFILE | LR_DEFAULTSIZE );
2157 /***********************************************************************
2158 * LoadCursorFromFileA (USER32.@)
2160 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
2162 TRACE("%s\n", debugstr_a(name));
2164 return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0,
2165 LR_LOADFROMFILE | LR_DEFAULTSIZE );
2168 /***********************************************************************
2169 * LoadIconW (USER32.@)
2171 HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
2173 TRACE("%p, %s\n", hInstance, debugstr_w(name));
2175 return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0,
2176 LR_SHARED | LR_DEFAULTSIZE );
2179 /***********************************************************************
2180 * LoadIconA (USER32.@)
2182 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
2184 TRACE("%p, %s\n", hInstance, debugstr_a(name));
2186 return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0,
2187 LR_SHARED | LR_DEFAULTSIZE );
2190 /**********************************************************************
2191 * GetIconInfo (USER32.@)
2193 BOOL WINAPI GetIconInfo(HICON hIcon, PICONINFO iconinfo)
2195 CURSORICONINFO *ciconinfo;
2196 INT height;
2198 ciconinfo = GlobalLock16(HICON_16(hIcon));
2199 if (!ciconinfo)
2200 return FALSE;
2202 TRACE("%p => %dx%d, %d bpp\n", hIcon,
2203 ciconinfo->nWidth, ciconinfo->nHeight, ciconinfo->bBitsPerPixel);
2205 if ( (ciconinfo->ptHotSpot.x == ICON_HOTSPOT) &&
2206 (ciconinfo->ptHotSpot.y == ICON_HOTSPOT) )
2208 iconinfo->fIcon = TRUE;
2209 iconinfo->xHotspot = ciconinfo->nWidth / 2;
2210 iconinfo->yHotspot = ciconinfo->nHeight / 2;
2212 else
2214 iconinfo->fIcon = FALSE;
2215 iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
2216 iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
2219 height = ciconinfo->nHeight;
2221 if (ciconinfo->bBitsPerPixel > 1)
2223 iconinfo->hbmColor = CreateBitmap( ciconinfo->nWidth, ciconinfo->nHeight,
2224 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
2225 (char *)(ciconinfo + 1)
2226 + ciconinfo->nHeight *
2227 get_bitmap_width_bytes (ciconinfo->nWidth,1) );
2229 else
2231 iconinfo->hbmColor = 0;
2232 height *= 2;
2235 iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, height,
2236 1, 1, (char *)(ciconinfo + 1));
2238 GlobalUnlock16(HICON_16(hIcon));
2240 return TRUE;
2243 /**********************************************************************
2244 * CreateIconIndirect (USER32.@)
2246 HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
2248 HCURSOR cursor;
2249 cursor_frame_t frame;
2250 DIBSECTION bmpXor;
2251 BITMAP bmpAnd;
2252 int xor_objsize = 0, sizeXor = 0, sizeAnd, planes, bpp;
2254 TRACE("color %p, mask %p, hotspot %ux%u, fIcon %d\n",
2255 iconinfo->hbmColor, iconinfo->hbmMask,
2256 iconinfo->xHotspot, iconinfo->yHotspot, iconinfo->fIcon);
2258 if (!iconinfo->hbmMask) return 0;
2260 planes = GetDeviceCaps( screen_dc, PLANES );
2261 bpp = GetDeviceCaps( screen_dc, BITSPIXEL );
2263 if (iconinfo->hbmColor)
2265 xor_objsize = GetObjectW( iconinfo->hbmColor, sizeof(bmpXor), &bmpXor );
2266 TRACE("color: width %d, height %d, width bytes %d, planes %u, bpp %u\n",
2267 bmpXor.dsBm.bmWidth, bmpXor.dsBm.bmHeight, bmpXor.dsBm.bmWidthBytes,
2268 bmpXor.dsBm.bmPlanes, bmpXor.dsBm.bmBitsPixel);
2269 /* we can use either depth 1 or screen depth for xor bitmap */
2270 if (bmpXor.dsBm.bmPlanes == 1 && bmpXor.dsBm.bmBitsPixel == 1) planes = bpp = 1;
2271 sizeXor = bmpXor.dsBm.bmHeight * planes * get_bitmap_width_bytes( bmpXor.dsBm.bmWidth, bpp );
2273 GetObjectW( iconinfo->hbmMask, sizeof(bmpAnd), &bmpAnd );
2274 TRACE("mask: width %d, height %d, width bytes %d, planes %u, bpp %u\n",
2275 bmpAnd.bmWidth, bmpAnd.bmHeight, bmpAnd.bmWidthBytes,
2276 bmpAnd.bmPlanes, bmpAnd.bmBitsPixel);
2278 sizeAnd = bmpAnd.bmHeight * get_bitmap_width_bytes(bmpAnd.bmWidth, 1);
2280 cursor = create_cursor( 1, 0 );
2282 /* If we are creating an icon, the hotspot is unused */
2283 if (iconinfo->fIcon)
2285 frame.xhot = ICON_HOTSPOT;
2286 frame.yhot = ICON_HOTSPOT;
2288 else
2290 frame.xhot = iconinfo->xHotspot;
2291 frame.yhot = iconinfo->yHotspot;
2294 if (iconinfo->hbmColor)
2296 frame.width = bmpXor.dsBm.bmWidth;
2297 frame.height = bmpXor.dsBm.bmHeight;
2298 frame.and_width_bytes = bmpAnd.bmWidthBytes;
2299 frame.xor_width_bytes = bmpXor.dsBm.bmWidthBytes;
2300 frame.planes = planes;
2301 frame.bpp = bpp;
2303 else
2305 frame.width = bmpAnd.bmWidth;
2306 frame.height = bmpAnd.bmHeight / 2;
2307 frame.and_width_bytes = get_bitmap_width_bytes(bmpAnd.bmWidth, 1);
2308 frame.xor_width_bytes = 0;
2309 frame.planes = 1;
2310 frame.bpp = 1;
2313 frame.bits = HeapAlloc( GetProcessHeap(), 0, sizeAnd + sizeXor );
2315 /* Some apps pass a color bitmap as a mask, convert it to b/w */
2316 if (bmpAnd.bmBitsPixel == 1)
2318 GetBitmapBits( iconinfo->hbmMask, sizeAnd, frame.bits );
2320 else
2322 HDC hdc, hdc_mem;
2323 HBITMAP hbmp_old, hbmp_mem_old, hbmp_mono;
2325 hdc = GetDC( 0 );
2326 hdc_mem = CreateCompatibleDC( hdc );
2328 hbmp_mono = CreateBitmap( bmpAnd.bmWidth, bmpAnd.bmHeight, 1, 1, NULL );
2330 hbmp_old = SelectObject( hdc, iconinfo->hbmMask );
2331 hbmp_mem_old = SelectObject( hdc_mem, hbmp_mono );
2333 BitBlt( hdc_mem, 0, 0, bmpAnd.bmWidth, bmpAnd.bmHeight, hdc, 0, 0, SRCCOPY );
2335 SelectObject( hdc, hbmp_old );
2336 SelectObject( hdc_mem, hbmp_mem_old );
2338 DeleteDC( hdc_mem );
2339 ReleaseDC( 0, hdc );
2341 GetBitmapBits( hbmp_mono, sizeAnd, frame.bits );
2342 DeleteObject( hbmp_mono );
2345 if (iconinfo->hbmColor)
2347 unsigned char *dst_bits = frame.bits + sizeAnd;
2349 if (bmpXor.dsBm.bmPlanes == planes && bmpXor.dsBm.bmBitsPixel == bpp)
2350 GetBitmapBits( iconinfo->hbmColor, sizeXor, dst_bits );
2351 else
2353 BITMAPINFO bminfo;
2354 int dib_width = get_dib_width_bytes( frame.width, frame.bpp );
2355 int bitmap_width = get_bitmap_width_bytes( frame.width, frame.bpp );
2357 bminfo.bmiHeader.biSize = sizeof(bminfo);
2358 bminfo.bmiHeader.biWidth = frame.width;
2359 bminfo.bmiHeader.biHeight = frame.height;
2360 bminfo.bmiHeader.biPlanes = frame.planes;
2361 bminfo.bmiHeader.biBitCount = frame.bpp;
2362 bminfo.bmiHeader.biCompression = BI_RGB;
2363 bminfo.bmiHeader.biSizeImage = frame.height * dib_width;
2364 bminfo.bmiHeader.biXPelsPerMeter = 0;
2365 bminfo.bmiHeader.biYPelsPerMeter = 0;
2366 bminfo.bmiHeader.biClrUsed = 0;
2367 bminfo.bmiHeader.biClrImportant = 0;
2369 /* swap lines for dib sections */
2370 if (xor_objsize == sizeof(DIBSECTION))
2371 bminfo.bmiHeader.biHeight = -bminfo.bmiHeader.biHeight;
2373 if (dib_width != bitmap_width) /* need to fixup alignment */
2375 char *src_bits = HeapAlloc( GetProcessHeap(), 0, bminfo.bmiHeader.biSizeImage );
2377 if (src_bits && GetDIBits( screen_dc, iconinfo->hbmColor, 0, frame.height,
2378 src_bits, &bminfo, DIB_RGB_COLORS ))
2380 int y;
2381 for (y = 0; y < frame.height; y++)
2382 memcpy( dst_bits + y * bitmap_width, src_bits + y * dib_width, bitmap_width );
2384 HeapFree( GetProcessHeap(), 0, src_bits );
2386 else
2387 GetDIBits( screen_dc, iconinfo->hbmColor, 0, frame.height,
2388 dst_bits, &bminfo, DIB_RGB_COLORS );
2391 set_cursor_frame( cursor, 0, &frame );
2392 HeapFree( GetProcessHeap(), 0, frame.bits );
2394 return cursor;
2397 /******************************************************************************
2398 * DrawIconEx (USER32.@) Draws an icon or cursor on device context
2400 * NOTES
2401 * Why is this using SM_CXICON instead of SM_CXCURSOR?
2403 * PARAMS
2404 * hdc [I] Handle to device context
2405 * x0 [I] X coordinate of upper left corner
2406 * y0 [I] Y coordinate of upper left corner
2407 * hIcon [I] Handle to icon to draw
2408 * cxWidth [I] Width of icon
2409 * cyWidth [I] Height of icon
2410 * istep [I] Index of frame in animated cursor
2411 * hbr [I] Handle to background brush
2412 * flags [I] Icon-drawing flags
2414 * RETURNS
2415 * Success: TRUE
2416 * Failure: FALSE
2418 BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
2419 INT cxWidth, INT cyWidth, UINT istep,
2420 HBRUSH hbr, UINT flags )
2422 CURSORICONINFO *ptr = GlobalLock16(HICON_16(hIcon));
2423 HDC hDC_off = 0, hMemDC;
2424 BOOL result = FALSE, DoOffscreen;
2425 HBITMAP hB_off = 0, hOld = 0;
2427 if (!ptr) return FALSE;
2428 TRACE_(icon)("(hdc=%p,pos=%d.%d,hicon=%p,extend=%d.%d,istep=%d,br=%p,flags=0x%08x)\n",
2429 hdc,x0,y0,hIcon,cxWidth,cyWidth,istep,hbr,flags );
2431 hMemDC = CreateCompatibleDC (hdc);
2432 if (istep)
2433 FIXME_(icon)("Ignoring istep=%d\n", istep);
2434 if (flags & DI_NOMIRROR)
2435 FIXME_(icon)("Ignoring flag DI_NOMIRROR\n");
2437 if (!flags) {
2438 FIXME_(icon)("no flags set? setting to DI_NORMAL\n");
2439 flags = DI_NORMAL;
2442 /* Calculate the size of the destination image. */
2443 if (cxWidth == 0)
2445 if (flags & DI_DEFAULTSIZE)
2446 cxWidth = GetSystemMetrics (SM_CXICON);
2447 else
2448 cxWidth = ptr->nWidth;
2450 if (cyWidth == 0)
2452 if (flags & DI_DEFAULTSIZE)
2453 cyWidth = GetSystemMetrics (SM_CYICON);
2454 else
2455 cyWidth = ptr->nHeight;
2458 DoOffscreen = (GetObjectType( hbr ) == OBJ_BRUSH);
2460 if (DoOffscreen) {
2461 RECT r;
2463 r.left = 0;
2464 r.top = 0;
2465 r.right = cxWidth;
2466 r.bottom = cxWidth;
2468 hDC_off = CreateCompatibleDC(hdc);
2469 hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth);
2470 if (hDC_off && hB_off) {
2471 hOld = SelectObject(hDC_off, hB_off);
2472 FillRect(hDC_off, &r, hbr);
2476 if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
2478 HBITMAP hXorBits, hAndBits;
2479 COLORREF oldFg, oldBg;
2480 INT nStretchMode;
2482 nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
2484 hXorBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
2485 ptr->bPlanes, ptr->bBitsPerPixel,
2486 (char *)(ptr + 1)
2487 + ptr->nHeight *
2488 get_bitmap_width_bytes(ptr->nWidth,1) );
2489 hAndBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
2490 1, 1, (char *)(ptr+1) );
2491 oldFg = SetTextColor( hdc, RGB(0,0,0) );
2492 oldBg = SetBkColor( hdc, RGB(255,255,255) );
2494 if (hXorBits && hAndBits)
2496 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
2497 if (flags & DI_MASK)
2499 if (DoOffscreen)
2500 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
2501 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
2502 else
2503 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
2504 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
2506 SelectObject( hMemDC, hXorBits );
2507 if (flags & DI_IMAGE)
2509 if (DoOffscreen)
2510 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
2511 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
2512 else
2513 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
2514 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
2516 SelectObject( hMemDC, hBitTemp );
2517 result = TRUE;
2520 SetTextColor( hdc, oldFg );
2521 SetBkColor( hdc, oldBg );
2522 if (hXorBits) DeleteObject( hXorBits );
2523 if (hAndBits) DeleteObject( hAndBits );
2524 SetStretchBltMode (hdc, nStretchMode);
2525 if (DoOffscreen) {
2526 BitBlt(hdc, x0, y0, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
2527 SelectObject(hDC_off, hOld);
2530 if (hMemDC) DeleteDC( hMemDC );
2531 if (hDC_off) DeleteDC(hDC_off);
2532 if (hB_off) DeleteObject(hB_off);
2533 GlobalUnlock16(HICON_16(hIcon));
2534 return result;
2537 /***********************************************************************
2538 * DIB_FixColorsToLoadflags
2540 * Change color table entries when LR_LOADTRANSPARENT or LR_LOADMAP3DCOLORS
2541 * are in loadflags
2543 static void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags, BYTE pix)
2545 int colors;
2546 COLORREF c_W, c_S, c_F, c_L, c_C;
2547 int incr,i;
2548 RGBQUAD *ptr;
2549 int bitmap_type;
2550 LONG width;
2551 LONG height;
2552 WORD bpp;
2553 DWORD compr;
2555 if (((bitmap_type = DIB_GetBitmapInfo((BITMAPINFOHEADER*) bmi, &width, &height, &bpp, &compr)) == -1))
2557 WARN_(resource)("Invalid bitmap\n");
2558 return;
2561 if (bpp > 8) return;
2563 if (bitmap_type == 0) /* BITMAPCOREHEADER */
2565 incr = 3;
2566 colors = 1 << bpp;
2568 else
2570 incr = 4;
2571 colors = bmi->bmiHeader.biClrUsed;
2572 if (colors > 256) colors = 256;
2573 if (!colors && (bpp <= 8)) colors = 1 << bpp;
2576 c_W = GetSysColor(COLOR_WINDOW);
2577 c_S = GetSysColor(COLOR_3DSHADOW);
2578 c_F = GetSysColor(COLOR_3DFACE);
2579 c_L = GetSysColor(COLOR_3DLIGHT);
2581 if (loadflags & LR_LOADTRANSPARENT) {
2582 switch (bpp) {
2583 case 1: pix = pix >> 7; break;
2584 case 4: pix = pix >> 4; break;
2585 case 8: break;
2586 default:
2587 WARN_(resource)("(%d): Unsupported depth\n", bpp);
2588 return;
2590 if (pix >= colors) {
2591 WARN_(resource)("pixel has color index greater than biClrUsed!\n");
2592 return;
2594 if (loadflags & LR_LOADMAP3DCOLORS) c_W = c_F;
2595 ptr = (RGBQUAD*)((char*)bmi->bmiColors+pix*incr);
2596 ptr->rgbBlue = GetBValue(c_W);
2597 ptr->rgbGreen = GetGValue(c_W);
2598 ptr->rgbRed = GetRValue(c_W);
2600 if (loadflags & LR_LOADMAP3DCOLORS)
2601 for (i=0; i<colors; i++) {
2602 ptr = (RGBQUAD*)((char*)bmi->bmiColors+i*incr);
2603 c_C = RGB(ptr->rgbRed, ptr->rgbGreen, ptr->rgbBlue);
2604 if (c_C == RGB(128, 128, 128)) {
2605 ptr->rgbRed = GetRValue(c_S);
2606 ptr->rgbGreen = GetGValue(c_S);
2607 ptr->rgbBlue = GetBValue(c_S);
2608 } else if (c_C == RGB(192, 192, 192)) {
2609 ptr->rgbRed = GetRValue(c_F);
2610 ptr->rgbGreen = GetGValue(c_F);
2611 ptr->rgbBlue = GetBValue(c_F);
2612 } else if (c_C == RGB(223, 223, 223)) {
2613 ptr->rgbRed = GetRValue(c_L);
2614 ptr->rgbGreen = GetGValue(c_L);
2615 ptr->rgbBlue = GetBValue(c_L);
2621 /**********************************************************************
2622 * BITMAP_Load
2624 static HBITMAP BITMAP_Load( HINSTANCE instance, LPCWSTR name,
2625 INT desiredx, INT desiredy, UINT loadflags )
2627 HBITMAP hbitmap = 0, orig_bm;
2628 HRSRC hRsrc;
2629 HGLOBAL handle;
2630 char *ptr = NULL;
2631 BITMAPINFO *info, *fix_info = NULL, *scaled_info = NULL;
2632 int size;
2633 BYTE pix;
2634 char *bits;
2635 LONG width, height, new_width, new_height;
2636 WORD bpp_dummy;
2637 DWORD compr_dummy;
2638 INT bm_type;
2639 HDC screen_mem_dc = NULL;
2641 if (!(loadflags & LR_LOADFROMFILE))
2643 if (!instance)
2645 /* OEM bitmap: try to load the resource from user32.dll */
2646 instance = user32_module;
2649 if (!(hRsrc = FindResourceW( instance, name, (LPWSTR)RT_BITMAP ))) return 0;
2650 if (!(handle = LoadResource( instance, hRsrc ))) return 0;
2652 if ((info = LockResource( handle )) == NULL) return 0;
2654 else
2656 BITMAPFILEHEADER * bmfh;
2658 if (!(ptr = map_fileW( name, NULL ))) return 0;
2659 info = (BITMAPINFO *)(ptr + sizeof(BITMAPFILEHEADER));
2660 bmfh = (BITMAPFILEHEADER *)ptr;
2661 if (!( bmfh->bfType == 0x4d42 /* 'BM' */ &&
2662 bmfh->bfReserved1 == 0 &&
2663 bmfh->bfReserved2 == 0))
2665 WARN("Invalid/unsupported bitmap format!\n");
2666 UnmapViewOfFile( ptr );
2667 return 0;
2671 size = bitmap_info_size(info, DIB_RGB_COLORS);
2672 fix_info = HeapAlloc(GetProcessHeap(), 0, size);
2673 scaled_info = HeapAlloc(GetProcessHeap(), 0, size);
2675 if (!fix_info || !scaled_info) goto end;
2676 memcpy(fix_info, info, size);
2678 pix = *((LPBYTE)info + size);
2679 DIB_FixColorsToLoadflags(fix_info, loadflags, pix);
2681 memcpy(scaled_info, fix_info, size);
2682 bm_type = DIB_GetBitmapInfo( &fix_info->bmiHeader, &width, &height,
2683 &bpp_dummy, &compr_dummy);
2684 if(desiredx != 0)
2685 new_width = desiredx;
2686 else
2687 new_width = width;
2689 if(desiredy != 0)
2690 new_height = height > 0 ? desiredy : -desiredy;
2691 else
2692 new_height = height;
2694 if(bm_type == 0)
2696 BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)&scaled_info->bmiHeader;
2697 core->bcWidth = new_width;
2698 core->bcHeight = new_height;
2700 else
2702 scaled_info->bmiHeader.biWidth = new_width;
2703 scaled_info->bmiHeader.biHeight = new_height;
2706 if (new_height < 0) new_height = -new_height;
2708 if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
2709 if (!(screen_mem_dc = CreateCompatibleDC( screen_dc ))) goto end;
2711 bits = (char *)info + size;
2713 if (loadflags & LR_CREATEDIBSECTION)
2715 scaled_info->bmiHeader.biCompression = 0; /* DIBSection can't be compressed */
2716 hbitmap = CreateDIBSection(screen_dc, scaled_info, DIB_RGB_COLORS, NULL, 0, 0);
2718 else
2720 if (is_dib_monochrome(fix_info))
2721 hbitmap = CreateBitmap(new_width, new_height, 1, 1, NULL);
2722 else
2723 hbitmap = CreateCompatibleBitmap(screen_dc, new_width, new_height);
2726 orig_bm = SelectObject(screen_mem_dc, hbitmap);
2727 StretchDIBits(screen_mem_dc, 0, 0, new_width, new_height, 0, 0, width, height, bits, fix_info, DIB_RGB_COLORS, SRCCOPY);
2728 SelectObject(screen_mem_dc, orig_bm);
2730 end:
2731 if (screen_mem_dc) DeleteDC(screen_mem_dc);
2732 HeapFree(GetProcessHeap(), 0, scaled_info);
2733 HeapFree(GetProcessHeap(), 0, fix_info);
2734 if (loadflags & LR_LOADFROMFILE) UnmapViewOfFile( ptr );
2736 return hbitmap;
2739 /**********************************************************************
2740 * LoadImageA (USER32.@)
2742 * See LoadImageW.
2744 HANDLE WINAPI LoadImageA( HINSTANCE hinst, LPCSTR name, UINT type,
2745 INT desiredx, INT desiredy, UINT loadflags)
2747 HANDLE res;
2748 LPWSTR u_name;
2750 if (!HIWORD(name))
2751 return LoadImageW(hinst, (LPCWSTR)name, type, desiredx, desiredy, loadflags);
2753 __TRY {
2754 DWORD len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
2755 u_name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2756 MultiByteToWideChar( CP_ACP, 0, name, -1, u_name, len );
2758 __EXCEPT_PAGE_FAULT {
2759 SetLastError( ERROR_INVALID_PARAMETER );
2760 return 0;
2762 __ENDTRY
2763 res = LoadImageW(hinst, u_name, type, desiredx, desiredy, loadflags);
2764 HeapFree(GetProcessHeap(), 0, u_name);
2765 return res;
2769 /******************************************************************************
2770 * LoadImageW (USER32.@) Loads an icon, cursor, or bitmap
2772 * PARAMS
2773 * hinst [I] Handle of instance that contains image
2774 * name [I] Name of image
2775 * type [I] Type of image
2776 * desiredx [I] Desired width
2777 * desiredy [I] Desired height
2778 * loadflags [I] Load flags
2780 * RETURNS
2781 * Success: Handle to newly loaded image
2782 * Failure: NULL
2784 * FIXME: Implementation lacks some features, see LR_ defines in winuser.h
2786 HANDLE WINAPI LoadImageW( HINSTANCE hinst, LPCWSTR name, UINT type,
2787 INT desiredx, INT desiredy, UINT loadflags )
2789 TRACE_(resource)("(%p,%s,%d,%d,%d,0x%08x)\n",
2790 hinst,debugstr_w(name),type,desiredx,desiredy,loadflags);
2792 if (loadflags & LR_DEFAULTSIZE) {
2793 if (type == IMAGE_ICON) {
2794 if (!desiredx) desiredx = GetSystemMetrics(SM_CXICON);
2795 if (!desiredy) desiredy = GetSystemMetrics(SM_CYICON);
2796 } else if (type == IMAGE_CURSOR) {
2797 if (!desiredx) desiredx = GetSystemMetrics(SM_CXCURSOR);
2798 if (!desiredy) desiredy = GetSystemMetrics(SM_CYCURSOR);
2801 if (loadflags & LR_LOADFROMFILE) loadflags &= ~LR_SHARED;
2802 switch (type) {
2803 case IMAGE_BITMAP:
2804 return BITMAP_Load( hinst, name, desiredx, desiredy, loadflags );
2806 case IMAGE_ICON:
2807 if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
2808 if (screen_dc)
2810 UINT palEnts = GetSystemPaletteEntries(screen_dc, 0, 0, NULL);
2811 if (palEnts == 0) palEnts = 256;
2812 return CURSORICON_Load(hinst, name, desiredx, desiredy,
2813 palEnts, FALSE, loadflags);
2815 break;
2817 case IMAGE_CURSOR:
2818 return CURSORICON_Load(hinst, name, desiredx, desiredy,
2819 1, TRUE, loadflags);
2821 return 0;
2824 /******************************************************************************
2825 * CopyImage (USER32.@) Creates new image and copies attributes to it
2827 * PARAMS
2828 * hnd [I] Handle to image to copy
2829 * type [I] Type of image to copy
2830 * desiredx [I] Desired width of new image
2831 * desiredy [I] Desired height of new image
2832 * flags [I] Copy flags
2834 * RETURNS
2835 * Success: Handle to newly created image
2836 * Failure: NULL
2838 * BUGS
2839 * Only Windows NT 4.0 supports the LR_COPYRETURNORG flag for bitmaps,
2840 * all other versions (95/2000/XP have been tested) ignore it.
2842 * NOTES
2843 * If LR_CREATEDIBSECTION is absent, the copy will be monochrome for
2844 * a monochrome source bitmap or if LR_MONOCHROME is present, otherwise
2845 * the copy will have the same depth as the screen.
2846 * The content of the image will only be copied if the bit depth of the
2847 * original image is compatible with the bit depth of the screen, or
2848 * if the source is a DIB section.
2849 * The LR_MONOCHROME flag is ignored if LR_CREATEDIBSECTION is present.
2851 HANDLE WINAPI CopyImage( HANDLE hnd, UINT type, INT desiredx,
2852 INT desiredy, UINT flags )
2854 TRACE("hnd=%p, type=%u, desiredx=%d, desiredy=%d, flags=%x\n",
2855 hnd, type, desiredx, desiredy, flags);
2857 switch (type)
2859 case IMAGE_BITMAP:
2861 HBITMAP res = NULL;
2862 DIBSECTION ds;
2863 int objSize;
2864 BITMAPINFO * bi;
2866 objSize = GetObjectW( hnd, sizeof(ds), &ds );
2867 if (!objSize) return 0;
2868 if ((desiredx < 0) || (desiredy < 0)) return 0;
2870 if (flags & LR_COPYFROMRESOURCE)
2872 FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
2875 if (desiredx == 0) desiredx = ds.dsBm.bmWidth;
2876 if (desiredy == 0) desiredy = ds.dsBm.bmHeight;
2878 /* Allocate memory for a BITMAPINFOHEADER structure and a
2879 color table. The maximum number of colors in a color table
2880 is 256 which corresponds to a bitmap with depth 8.
2881 Bitmaps with higher depths don't have color tables. */
2882 bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2883 if (!bi) return 0;
2885 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
2886 bi->bmiHeader.biPlanes = ds.dsBm.bmPlanes;
2887 bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
2888 bi->bmiHeader.biCompression = BI_RGB;
2890 if (flags & LR_CREATEDIBSECTION)
2892 /* Create a DIB section. LR_MONOCHROME is ignored */
2893 void * bits;
2894 HDC dc = CreateCompatibleDC(NULL);
2896 if (objSize == sizeof(DIBSECTION))
2898 /* The source bitmap is a DIB.
2899 Get its attributes to create an exact copy */
2900 memcpy(bi, &ds.dsBmih, sizeof(BITMAPINFOHEADER));
2903 /* Get the color table or the color masks */
2904 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
2906 bi->bmiHeader.biWidth = desiredx;
2907 bi->bmiHeader.biHeight = desiredy;
2908 bi->bmiHeader.biSizeImage = 0;
2910 res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
2911 DeleteDC(dc);
2913 else
2915 /* Create a device-dependent bitmap */
2917 BOOL monochrome = (flags & LR_MONOCHROME);
2919 if (objSize == sizeof(DIBSECTION))
2921 /* The source bitmap is a DIB section.
2922 Get its attributes */
2923 HDC dc = CreateCompatibleDC(NULL);
2924 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
2925 bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
2926 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
2927 DeleteDC(dc);
2929 if (!monochrome && ds.dsBm.bmBitsPixel == 1)
2931 /* Look if the colors of the DIB are black and white */
2933 monochrome =
2934 (bi->bmiColors[0].rgbRed == 0xff
2935 && bi->bmiColors[0].rgbGreen == 0xff
2936 && bi->bmiColors[0].rgbBlue == 0xff
2937 && bi->bmiColors[0].rgbReserved == 0
2938 && bi->bmiColors[1].rgbRed == 0
2939 && bi->bmiColors[1].rgbGreen == 0
2940 && bi->bmiColors[1].rgbBlue == 0
2941 && bi->bmiColors[1].rgbReserved == 0)
2943 (bi->bmiColors[0].rgbRed == 0
2944 && bi->bmiColors[0].rgbGreen == 0
2945 && bi->bmiColors[0].rgbBlue == 0
2946 && bi->bmiColors[0].rgbReserved == 0
2947 && bi->bmiColors[1].rgbRed == 0xff
2948 && bi->bmiColors[1].rgbGreen == 0xff
2949 && bi->bmiColors[1].rgbBlue == 0xff
2950 && bi->bmiColors[1].rgbReserved == 0);
2953 else if (!monochrome)
2955 monochrome = ds.dsBm.bmBitsPixel == 1;
2958 if (monochrome)
2960 res = CreateBitmap(desiredx, desiredy, 1, 1, NULL);
2962 else
2964 HDC screenDC = GetDC(NULL);
2965 res = CreateCompatibleBitmap(screenDC, desiredx, desiredy);
2966 ReleaseDC(NULL, screenDC);
2970 if (res)
2972 /* Only copy the bitmap if it's a DIB section or if it's
2973 compatible to the screen */
2974 BOOL copyContents;
2976 if (objSize == sizeof(DIBSECTION))
2978 copyContents = TRUE;
2980 else
2982 HDC screenDC = GetDC(NULL);
2983 int screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
2984 ReleaseDC(NULL, screenDC);
2986 copyContents = (ds.dsBm.bmBitsPixel == 1 || ds.dsBm.bmBitsPixel == screen_depth);
2989 if (copyContents)
2991 /* The source bitmap may already be selected in a device context,
2992 use GetDIBits/StretchDIBits and not StretchBlt */
2994 HDC dc;
2995 void * bits;
2997 dc = CreateCompatibleDC(NULL);
2999 bi->bmiHeader.biWidth = ds.dsBm.bmWidth;
3000 bi->bmiHeader.biHeight = ds.dsBm.bmHeight;
3001 bi->bmiHeader.biSizeImage = 0;
3002 bi->bmiHeader.biClrUsed = 0;
3003 bi->bmiHeader.biClrImportant = 0;
3005 /* Fill in biSizeImage */
3006 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
3007 bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bi->bmiHeader.biSizeImage);
3009 if (bits)
3011 HBITMAP oldBmp;
3013 /* Get the image bits of the source bitmap */
3014 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS);
3016 /* Copy it to the destination bitmap */
3017 oldBmp = SelectObject(dc, res);
3018 StretchDIBits(dc, 0, 0, desiredx, desiredy,
3019 0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight,
3020 bits, bi, DIB_RGB_COLORS, SRCCOPY);
3021 SelectObject(dc, oldBmp);
3023 HeapFree(GetProcessHeap(), 0, bits);
3026 DeleteDC(dc);
3029 if (flags & LR_COPYDELETEORG)
3031 DeleteObject(hnd);
3034 HeapFree(GetProcessHeap(), 0, bi);
3035 return res;
3037 case IMAGE_ICON:
3038 return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags);
3039 case IMAGE_CURSOR:
3040 /* Should call CURSORICON_ExtCopy but more testing
3041 * needs to be done before we change this
3043 if (flags) FIXME("Flags are ignored\n");
3044 return CopyCursor(hnd);
3046 return 0;
3050 /******************************************************************************
3051 * LoadBitmapW (USER32.@) Loads bitmap from the executable file
3053 * RETURNS
3054 * Success: Handle to specified bitmap
3055 * Failure: NULL
3057 HBITMAP WINAPI LoadBitmapW(
3058 HINSTANCE instance, /* [in] Handle to application instance */
3059 LPCWSTR name) /* [in] Address of bitmap resource name */
3061 return LoadImageW( instance, name, IMAGE_BITMAP, 0, 0, 0 );
3064 /**********************************************************************
3065 * LoadBitmapA (USER32.@)
3067 * See LoadBitmapW.
3069 HBITMAP WINAPI LoadBitmapA( HINSTANCE instance, LPCSTR name )
3071 return LoadImageA( instance, name, IMAGE_BITMAP, 0, 0, 0 );