winebrowser: Add support for XTYP_REQUEST in DDE callback.
[wine.git] / dlls / user32 / cursoricon.c
blobd528bee7d0aaf42ea3d3be94c9d6fb64b1fbc829
1 /*
2 * Cursor and icon support
4 * Copyright 1995 Alexandre Julliard
5 * 1996 Martin Von Loewis
6 * 1997 Alex Korobka
7 * 1998 Turchanov Sergey
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 * Theory:
27 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwui/html/msdn_icons.asp
29 * Cursors and icons are stored in a global heap block, with the
30 * following layout:
32 * CURSORICONINFO info;
33 * BYTE[] ANDbits;
34 * BYTE[] XORbits;
36 * The bits structures are in the format of a device-dependent bitmap.
38 * This layout is very sub-optimal, as the bitmap bits are stored in
39 * the X client instead of in the server like other bitmaps; however,
40 * some programs (notably Paint Brush) expect to be able to manipulate
41 * the bits directly :-(
43 * FIXME: what are we going to do with animation and color (bpp > 1) cursors ?!
46 #include "config.h"
47 #include "wine/port.h"
49 #include <stdarg.h>
50 #include <string.h>
51 #include <stdlib.h>
53 #include "windef.h"
54 #include "winbase.h"
55 #include "wingdi.h"
56 #include "winerror.h"
57 #include "wine/winbase16.h"
58 #include "wine/winuser16.h"
59 #include "wine/exception.h"
60 #include "wine/debug.h"
61 #include "user_private.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(cursor);
64 WINE_DECLARE_DEBUG_CHANNEL(icon);
65 WINE_DECLARE_DEBUG_CHANNEL(resource);
67 #include "pshpack1.h"
69 typedef struct {
70 BYTE bWidth;
71 BYTE bHeight;
72 BYTE bColorCount;
73 BYTE bReserved;
74 WORD xHotspot;
75 WORD yHotspot;
76 DWORD dwDIBSize;
77 DWORD dwDIBOffset;
78 } CURSORICONFILEDIRENTRY;
80 typedef struct
82 WORD idReserved;
83 WORD idType;
84 WORD idCount;
85 CURSORICONFILEDIRENTRY idEntries[1];
86 } CURSORICONFILEDIR;
88 #include "poppack.h"
90 #define CID_RESOURCE 0x0001
91 #define CID_WIN32 0x0004
92 #define CID_NONSHARED 0x0008
94 static RECT CURSOR_ClipRect; /* Cursor clipping rect */
96 static HDC screen_dc;
98 static const WCHAR DISPLAYW[] = {'D','I','S','P','L','A','Y',0};
100 /**********************************************************************
101 * ICONCACHE for cursors/icons loaded with LR_SHARED.
103 * FIXME: This should not be allocated on the system heap, but on a
104 * subsystem-global heap (i.e. one for all Win16 processes,
105 * and one for each Win32 process).
107 typedef struct tagICONCACHE
109 struct tagICONCACHE *next;
111 HMODULE hModule;
112 HRSRC hRsrc;
113 HRSRC hGroupRsrc;
114 HICON hIcon;
116 INT count;
118 } ICONCACHE;
120 static ICONCACHE *IconAnchor = NULL;
122 static CRITICAL_SECTION IconCrst;
123 static CRITICAL_SECTION_DEBUG critsect_debug =
125 0, 0, &IconCrst,
126 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
127 0, 0, { (DWORD_PTR)(__FILE__ ": IconCrst") }
129 static CRITICAL_SECTION IconCrst = { &critsect_debug, -1, 0, 0, 0, 0 };
131 static const WORD ICON_HOTSPOT = 0x4242;
134 /***********************************************************************
135 * map_fileW
137 * Helper function to map a file to memory:
138 * name - file name
139 * [RETURN] ptr - pointer to mapped file
140 * [RETURN] filesize - pointer size of file to be stored if not NULL
142 static void *map_fileW( LPCWSTR name, LPDWORD filesize )
144 HANDLE hFile, hMapping;
145 LPVOID ptr = NULL;
147 hFile = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL,
148 OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0 );
149 if (hFile != INVALID_HANDLE_VALUE)
151 hMapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
152 if (hMapping)
154 ptr = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
155 CloseHandle( hMapping );
156 if (filesize)
157 *filesize = GetFileSize( hFile, NULL );
159 CloseHandle( hFile );
161 return ptr;
165 /***********************************************************************
166 * get_bitmap_width_bytes
168 * Return number of bytes taken by a scanline of 16-bit aligned Windows DDB
169 * data.
171 static int get_bitmap_width_bytes( int width, int bpp )
173 switch(bpp)
175 case 1:
176 return 2 * ((width+15) / 16);
177 case 4:
178 return 2 * ((width+3) / 4);
179 case 24:
180 width *= 3;
181 /* fall through */
182 case 8:
183 return width + (width & 1);
184 case 16:
185 case 15:
186 return width * 2;
187 case 32:
188 return width * 4;
189 default:
190 WARN("Unknown depth %d, please report.\n", bpp );
192 return -1;
196 /***********************************************************************
197 * get_dib_width_bytes
199 * Return the width of a DIB bitmap in bytes. DIB bitmap data is 32-bit aligned.
201 static int get_dib_width_bytes( int width, int depth )
203 int words;
205 switch(depth)
207 case 1: words = (width + 31) / 32; break;
208 case 4: words = (width + 7) / 8; break;
209 case 8: words = (width + 3) / 4; break;
210 case 15:
211 case 16: words = (width + 1) / 2; break;
212 case 24: words = (width * 3 + 3)/4; break;
213 default:
214 WARN("(%d): Unsupported depth\n", depth );
215 /* fall through */
216 case 32:
217 words = width;
219 return 4 * words;
223 /***********************************************************************
224 * bitmap_info_size
226 * Return the size of the bitmap info structure including color table.
228 static int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
230 int colors;
232 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
234 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
235 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
236 return sizeof(BITMAPCOREHEADER) + colors *
237 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
239 else /* assume BITMAPINFOHEADER */
241 colors = info->bmiHeader.biClrUsed;
242 if (colors > 256) /* buffer overflow otherwise */
243 colors = 256;
244 if (!colors && (info->bmiHeader.biBitCount <= 8))
245 colors = 1 << info->bmiHeader.biBitCount;
246 return sizeof(BITMAPINFOHEADER) + colors *
247 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
252 /***********************************************************************
253 * is_dib_monochrome
255 * Returns whether a DIB can be converted to a monochrome DDB.
257 * A DIB can be converted if its color table contains only black and
258 * white. Black must be the first color in the color table.
260 * Note : If the first color in the color table is white followed by
261 * black, we can't convert it to a monochrome DDB with
262 * SetDIBits, because black and white would be inverted.
264 static BOOL is_dib_monochrome( const BITMAPINFO* info )
266 if (info->bmiHeader.biBitCount != 1) return FALSE;
268 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
270 const RGBTRIPLE *rgb = ((const BITMAPCOREINFO*)info)->bmciColors;
272 /* Check if the first color is black */
273 if ((rgb->rgbtRed == 0) && (rgb->rgbtGreen == 0) && (rgb->rgbtBlue == 0))
275 rgb++;
277 /* Check if the second color is white */
278 return ((rgb->rgbtRed == 0xff) && (rgb->rgbtGreen == 0xff)
279 && (rgb->rgbtBlue == 0xff));
281 else return FALSE;
283 else /* assume BITMAPINFOHEADER */
285 const RGBQUAD *rgb = info->bmiColors;
287 /* Check if the first color is black */
288 if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) &&
289 (rgb->rgbBlue == 0) && (rgb->rgbReserved == 0))
291 rgb++;
293 /* Check if the second color is white */
294 return ((rgb->rgbRed == 0xff) && (rgb->rgbGreen == 0xff)
295 && (rgb->rgbBlue == 0xff) && (rgb->rgbReserved == 0));
297 else return FALSE;
301 /***********************************************************************
302 * DIB_GetBitmapInfo
304 * Get the info from a bitmap header.
305 * Return 1 for INFOHEADER, 0 for COREHEADER,
306 * 4 for V4HEADER, 5 for V5HEADER, -1 for error.
308 static int DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width,
309 LONG *height, WORD *bpp, DWORD *compr )
311 if (header->biSize == sizeof(BITMAPINFOHEADER))
313 *width = header->biWidth;
314 *height = header->biHeight;
315 *bpp = header->biBitCount;
316 *compr = header->biCompression;
317 return 1;
319 if (header->biSize == sizeof(BITMAPCOREHEADER))
321 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header;
322 *width = core->bcWidth;
323 *height = core->bcHeight;
324 *bpp = core->bcBitCount;
325 *compr = 0;
326 return 0;
328 if (header->biSize == sizeof(BITMAPV4HEADER))
330 const BITMAPV4HEADER *v4hdr = (const BITMAPV4HEADER *)header;
331 *width = v4hdr->bV4Width;
332 *height = v4hdr->bV4Height;
333 *bpp = v4hdr->bV4BitCount;
334 *compr = v4hdr->bV4V4Compression;
335 return 4;
337 if (header->biSize == sizeof(BITMAPV5HEADER))
339 const BITMAPV5HEADER *v5hdr = (const BITMAPV5HEADER *)header;
340 *width = v5hdr->bV5Width;
341 *height = v5hdr->bV5Height;
342 *bpp = v5hdr->bV5BitCount;
343 *compr = v5hdr->bV5Compression;
344 return 5;
346 ERR("(%d): unknown/wrong size for header\n", header->biSize );
347 return -1;
350 /**********************************************************************
351 * CURSORICON_FindSharedIcon
353 static HICON CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
355 HICON hIcon = 0;
356 ICONCACHE *ptr;
358 EnterCriticalSection( &IconCrst );
360 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
361 if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
363 ptr->count++;
364 hIcon = ptr->hIcon;
365 break;
368 LeaveCriticalSection( &IconCrst );
370 return hIcon;
373 /*************************************************************************
374 * CURSORICON_FindCache
376 * Given a handle, find the corresponding cache element
378 * PARAMS
379 * Handle [I] handle to an Image
381 * RETURNS
382 * Success: The cache entry
383 * Failure: NULL
386 static ICONCACHE* CURSORICON_FindCache(HICON hIcon)
388 ICONCACHE *ptr;
389 ICONCACHE *pRet=NULL;
390 BOOL IsFound = FALSE;
391 int count;
393 EnterCriticalSection( &IconCrst );
395 for (count = 0, ptr = IconAnchor; ptr != NULL && !IsFound; ptr = ptr->next, count++ )
397 if ( hIcon == ptr->hIcon )
399 IsFound = TRUE;
400 pRet = ptr;
404 LeaveCriticalSection( &IconCrst );
406 return pRet;
409 /**********************************************************************
410 * CURSORICON_AddSharedIcon
412 static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HRSRC hGroupRsrc, HICON hIcon )
414 ICONCACHE *ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(ICONCACHE) );
415 if ( !ptr ) return;
417 ptr->hModule = hModule;
418 ptr->hRsrc = hRsrc;
419 ptr->hIcon = hIcon;
420 ptr->hGroupRsrc = hGroupRsrc;
421 ptr->count = 1;
423 EnterCriticalSection( &IconCrst );
424 ptr->next = IconAnchor;
425 IconAnchor = ptr;
426 LeaveCriticalSection( &IconCrst );
429 /**********************************************************************
430 * CURSORICON_DelSharedIcon
432 static INT CURSORICON_DelSharedIcon( HICON hIcon )
434 INT count = -1;
435 ICONCACHE *ptr;
437 EnterCriticalSection( &IconCrst );
439 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
440 if ( ptr->hIcon == hIcon )
442 if ( ptr->count > 0 ) ptr->count--;
443 count = ptr->count;
444 break;
447 LeaveCriticalSection( &IconCrst );
449 return count;
452 /**********************************************************************
453 * CURSORICON_FreeModuleIcons
455 void CURSORICON_FreeModuleIcons( HMODULE16 hMod16 )
457 ICONCACHE **ptr = &IconAnchor;
458 HMODULE hModule = HMODULE_32(GetExePtr( hMod16 ));
460 EnterCriticalSection( &IconCrst );
462 while ( *ptr )
464 if ( (*ptr)->hModule == hModule )
466 ICONCACHE *freePtr = *ptr;
467 *ptr = freePtr->next;
469 GlobalFree16(HICON_16(freePtr->hIcon));
470 HeapFree( GetProcessHeap(), 0, freePtr );
471 continue;
473 ptr = &(*ptr)->next;
476 LeaveCriticalSection( &IconCrst );
480 * The following macro functions account for the irregularities of
481 * accessing cursor and icon resources in files and resource entries.
483 typedef BOOL (*fnGetCIEntry)( LPVOID dir, int n,
484 int *width, int *height, int *bits );
486 /**********************************************************************
487 * CURSORICON_FindBestIcon
489 * Find the icon closest to the requested size and number of colors.
491 static int CURSORICON_FindBestIcon( LPVOID dir, fnGetCIEntry get_entry,
492 int width, int height, int colors )
494 int i, cx, cy, bits, bestEntry = -1;
495 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
496 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
498 /* Find Best Fit */
499 iTotalDiff = 0xFFFFFFFF;
500 iColorDiff = 0xFFFFFFFF;
501 for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
503 iTempXDiff = abs(width - cx);
504 iTempYDiff = abs(height - cy);
506 if(iTotalDiff > (iTempXDiff + iTempYDiff))
508 iXDiff = iTempXDiff;
509 iYDiff = iTempYDiff;
510 iTotalDiff = iXDiff + iYDiff;
514 /* Find Best Colors for Best Fit */
515 for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
517 if(abs(width - cx) == iXDiff && abs(height - cy) == iYDiff)
519 iTempColorDiff = abs(colors - (1<<bits));
520 if(iColorDiff > iTempColorDiff)
522 bestEntry = i;
523 iColorDiff = iTempColorDiff;
528 return bestEntry;
531 static BOOL CURSORICON_GetResIconEntry( LPVOID dir, int n,
532 int *width, int *height, int *bits )
534 CURSORICONDIR *resdir = dir;
535 ICONRESDIR *icon;
537 if ( resdir->idCount <= n )
538 return FALSE;
539 icon = &resdir->idEntries[n].ResInfo.icon;
540 *width = icon->bWidth;
541 *height = icon->bHeight;
542 *bits = resdir->idEntries[n].wBitCount;
543 return TRUE;
546 /**********************************************************************
547 * CURSORICON_FindBestCursor
549 * Find the cursor closest to the requested size.
550 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
551 * ignored too
553 static int CURSORICON_FindBestCursor( LPVOID dir, fnGetCIEntry get_entry,
554 int width, int height, int color )
556 int i, maxwidth, maxheight, cx, cy, bits, bestEntry = -1;
558 /* Double height to account for AND and XOR masks */
560 height *= 2;
562 /* First find the largest one smaller than or equal to the requested size*/
564 maxwidth = maxheight = 0;
565 for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
567 if ((cx <= width) && (cy <= height) &&
568 (cx > maxwidth) && (cy > maxheight) &&
569 (bits == 1))
571 bestEntry = i;
572 maxwidth = cx;
573 maxheight = cy;
576 if (bestEntry != -1) return bestEntry;
578 /* Now find the smallest one larger than the requested size */
580 maxwidth = maxheight = 255;
581 for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
583 if (((cx < maxwidth) && (cy < maxheight) && (bits == 1)) ||
584 (bestEntry==-1))
586 bestEntry = i;
587 maxwidth = cx;
588 maxheight = cy;
592 return bestEntry;
595 static BOOL CURSORICON_GetResCursorEntry( LPVOID dir, int n,
596 int *width, int *height, int *bits )
598 CURSORICONDIR *resdir = dir;
599 CURSORDIR *cursor;
601 if ( resdir->idCount <= n )
602 return FALSE;
603 cursor = &resdir->idEntries[n].ResInfo.cursor;
604 *width = cursor->wWidth;
605 *height = cursor->wHeight;
606 *bits = resdir->idEntries[n].wBitCount;
607 return TRUE;
610 static CURSORICONDIRENTRY *CURSORICON_FindBestIconRes( CURSORICONDIR * dir,
611 int width, int height, int colors )
613 int n;
615 n = CURSORICON_FindBestIcon( dir, CURSORICON_GetResIconEntry,
616 width, height, colors );
617 if ( n < 0 )
618 return NULL;
619 return &dir->idEntries[n];
622 static CURSORICONDIRENTRY *CURSORICON_FindBestCursorRes( CURSORICONDIR *dir,
623 int width, int height, int color )
625 int n = CURSORICON_FindBestCursor( dir, CURSORICON_GetResCursorEntry,
626 width, height, color );
627 if ( n < 0 )
628 return NULL;
629 return &dir->idEntries[n];
632 static BOOL CURSORICON_GetFileEntry( LPVOID dir, int n,
633 int *width, int *height, int *bits )
635 CURSORICONFILEDIR *filedir = dir;
636 CURSORICONFILEDIRENTRY *entry;
638 if ( filedir->idCount <= n )
639 return FALSE;
640 entry = &filedir->idEntries[n];
641 *width = entry->bWidth;
642 *height = entry->bHeight;
643 *bits = entry->bColorCount;
644 return TRUE;
647 static CURSORICONFILEDIRENTRY *CURSORICON_FindBestCursorFile( CURSORICONFILEDIR *dir,
648 int width, int height, int color )
650 int n = CURSORICON_FindBestCursor( dir, CURSORICON_GetFileEntry,
651 width, height, color );
652 if ( n < 0 )
653 return NULL;
654 return &dir->idEntries[n];
657 static CURSORICONFILEDIRENTRY *CURSORICON_FindBestIconFile( CURSORICONFILEDIR *dir,
658 int width, int height, int color )
660 int n = CURSORICON_FindBestIcon( dir, CURSORICON_GetFileEntry,
661 width, height, color );
662 if ( n < 0 )
663 return NULL;
664 return &dir->idEntries[n];
667 /**********************************************************************
668 * CreateIconFromResourceEx (USER32.@)
670 * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
671 * with cbSize parameter as well.
673 HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
674 BOOL bIcon, DWORD dwVersion,
675 INT width, INT height,
676 UINT cFlag )
678 HGLOBAL16 hObj;
679 static HDC hdcMem;
680 int sizeAnd, sizeXor;
681 HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
682 BITMAP bmpXor, bmpAnd;
683 POINT16 hotspot;
684 BITMAPINFO *bmi;
685 BOOL DoStretch;
686 INT size;
688 hotspot.x = ICON_HOTSPOT;
689 hotspot.y = ICON_HOTSPOT;
691 TRACE_(cursor)("%p (%u bytes), ver %08x, %ix%i %s %s\n",
692 bits, cbSize, (unsigned)dwVersion, width, height,
693 bIcon ? "icon" : "cursor", (cFlag & LR_MONOCHROME) ? "mono" : "" );
694 if (dwVersion == 0x00020000)
696 FIXME_(cursor)("\t2.xx resources are not supported\n");
697 return 0;
700 if (bIcon)
701 bmi = (BITMAPINFO *)bits;
702 else /* get the hotspot */
704 POINT16 *pt = (POINT16 *)bits;
705 hotspot = *pt;
706 bmi = (BITMAPINFO *)(pt + 1);
708 size = bitmap_info_size( bmi, DIB_RGB_COLORS );
710 if (!width) width = bmi->bmiHeader.biWidth;
711 if (!height) height = bmi->bmiHeader.biHeight/2;
712 DoStretch = (bmi->bmiHeader.biHeight/2 != height) ||
713 (bmi->bmiHeader.biWidth != width);
715 /* Check bitmap header */
717 if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
718 (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) ||
719 bmi->bmiHeader.biCompression != BI_RGB) )
721 WARN_(cursor)("\tinvalid resource bitmap header.\n");
722 return 0;
725 if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
726 if (screen_dc)
728 BITMAPINFO* pInfo;
730 /* Make sure we have room for the monochrome bitmap later on.
731 * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
732 * up to and including the biBitCount. In-memory icon resource
733 * format is as follows:
735 * BITMAPINFOHEADER icHeader // DIB header
736 * RGBQUAD icColors[] // Color table
737 * BYTE icXOR[] // DIB bits for XOR mask
738 * BYTE icAND[] // DIB bits for AND mask
741 if ((pInfo = HeapAlloc( GetProcessHeap(), 0,
742 max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))))
744 memcpy( pInfo, bmi, size );
745 pInfo->bmiHeader.biHeight /= 2;
747 /* Create the XOR bitmap */
749 if (DoStretch) {
750 if(bIcon)
752 hXorBits = CreateCompatibleBitmap(screen_dc, width, height);
754 else
756 hXorBits = CreateBitmap(width, height, 1, 1, NULL);
758 if(hXorBits)
760 HBITMAP hOld;
761 BOOL res = FALSE;
763 if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
764 if (hdcMem) {
765 hOld = SelectObject(hdcMem, hXorBits);
766 res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
767 bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2,
768 (char*)bmi + size, pInfo, DIB_RGB_COLORS, SRCCOPY);
769 SelectObject(hdcMem, hOld);
771 if (!res) { DeleteObject(hXorBits); hXorBits = 0; }
773 } else {
774 if (is_dib_monochrome(bmi)) {
775 hXorBits = CreateBitmap(width, height, 1, 1, NULL);
776 SetDIBits(screen_dc, hXorBits, 0, height,
777 (char*)bmi + size, pInfo, DIB_RGB_COLORS);
779 else
780 hXorBits = CreateDIBitmap(screen_dc, &pInfo->bmiHeader,
781 CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS);
784 if( hXorBits )
786 char* xbits = (char *)bmi + size +
787 get_dib_width_bytes( bmi->bmiHeader.biWidth,
788 bmi->bmiHeader.biBitCount ) * abs( bmi->bmiHeader.biHeight ) / 2;
790 pInfo->bmiHeader.biBitCount = 1;
791 if (pInfo->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
793 RGBQUAD *rgb = pInfo->bmiColors;
795 pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
796 rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
797 rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
798 rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
800 else
802 RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
804 rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
805 rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
808 /* Create the AND bitmap */
810 if (DoStretch) {
811 if ((hAndBits = CreateBitmap(width, height, 1, 1, NULL))) {
812 HBITMAP hOld;
813 BOOL res = FALSE;
815 if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
816 if (hdcMem) {
817 hOld = SelectObject(hdcMem, hAndBits);
818 res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
819 pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight,
820 xbits, pInfo, DIB_RGB_COLORS, SRCCOPY);
821 SelectObject(hdcMem, hOld);
823 if (!res) { DeleteObject(hAndBits); hAndBits = 0; }
825 } else {
826 hAndBits = CreateBitmap(width, height, 1, 1, NULL);
828 if (hAndBits) SetDIBits(screen_dc, hAndBits, 0, height,
829 xbits, pInfo, DIB_RGB_COLORS);
832 if( !hAndBits ) DeleteObject( hXorBits );
834 HeapFree( GetProcessHeap(), 0, pInfo );
838 if( !hXorBits || !hAndBits )
840 WARN_(cursor)("\tunable to create an icon bitmap.\n");
841 return 0;
844 /* Now create the CURSORICONINFO structure */
845 GetObjectA( hXorBits, sizeof(bmpXor), &bmpXor );
846 GetObjectA( hAndBits, sizeof(bmpAnd), &bmpAnd );
847 sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
848 sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
850 hObj = GlobalAlloc16( GMEM_MOVEABLE,
851 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
852 if (hObj)
854 CURSORICONINFO *info;
856 info = (CURSORICONINFO *)GlobalLock16( hObj );
857 info->ptHotSpot.x = hotspot.x;
858 info->ptHotSpot.y = hotspot.y;
859 info->nWidth = bmpXor.bmWidth;
860 info->nHeight = bmpXor.bmHeight;
861 info->nWidthBytes = bmpXor.bmWidthBytes;
862 info->bPlanes = bmpXor.bmPlanes;
863 info->bBitsPerPixel = bmpXor.bmBitsPixel;
865 /* Transfer the bitmap bits to the CURSORICONINFO structure */
867 GetBitmapBits( hAndBits, sizeAnd, (char *)(info + 1) );
868 GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
869 GlobalUnlock16( hObj );
872 DeleteObject( hAndBits );
873 DeleteObject( hXorBits );
874 return HICON_32((HICON16)hObj);
878 /**********************************************************************
879 * CreateIconFromResource (USER32.@)
881 HICON WINAPI CreateIconFromResource( LPBYTE bits, UINT cbSize,
882 BOOL bIcon, DWORD dwVersion)
884 return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
888 static HICON CURSORICON_LoadFromFile( LPCWSTR filename,
889 INT width, INT height, INT colors,
890 BOOL fCursor, UINT loadflags)
892 CURSORICONFILEDIRENTRY *entry;
893 CURSORICONFILEDIR *dir;
894 DWORD filesize = 0;
895 HICON hIcon = 0;
896 LPBYTE bits;
898 TRACE("loading %s\n", debugstr_w( filename ));
900 bits = map_fileW( filename, &filesize );
901 if (!bits)
902 return hIcon;
904 dir = (CURSORICONFILEDIR*) bits;
905 if ( filesize < sizeof(*dir) )
906 goto end;
908 if ( filesize < (sizeof(*dir) + sizeof(dir->idEntries[0])*(dir->idCount-1)) )
909 goto end;
911 if ( fCursor )
912 entry = CURSORICON_FindBestCursorFile( dir, width, height, 1 );
913 else
914 entry = CURSORICON_FindBestIconFile( dir, width, height, colors );
916 if ( !entry )
917 goto end;
919 /* check that we don't run off the end of the file */
920 if ( entry->dwDIBOffset > filesize )
921 goto end;
922 if ( entry->dwDIBOffset + entry->dwDIBSize > filesize )
923 goto end;
925 hIcon = CreateIconFromResourceEx( &bits[entry->dwDIBOffset], entry->dwDIBSize,
926 !fCursor, 0x00030000, width, height, loadflags );
927 end:
928 TRACE("loaded %s -> %p\n", debugstr_w( filename ), hIcon );
929 UnmapViewOfFile( bits );
930 return hIcon;
933 /**********************************************************************
934 * CURSORICON_Load
936 * Load a cursor or icon from resource or file.
938 static HICON CURSORICON_Load(HINSTANCE hInstance, LPCWSTR name,
939 INT width, INT height, INT colors,
940 BOOL fCursor, UINT loadflags)
942 HANDLE handle = 0;
943 HICON hIcon = 0;
944 HRSRC hRsrc, hGroupRsrc;
945 CURSORICONDIR *dir;
946 CURSORICONDIRENTRY *dirEntry;
947 LPBYTE bits;
948 WORD wResId;
949 DWORD dwBytesInRes;
951 TRACE("%p, %s, %dx%d, colors %d, fCursor %d, flags 0x%04x\n",
952 hInstance, debugstr_w(name), width, height, colors, fCursor, loadflags);
954 if ( loadflags & LR_LOADFROMFILE ) /* Load from file */
955 return CURSORICON_LoadFromFile( name, width, height, colors, fCursor, loadflags );
957 if (!hInstance) hInstance = user32_module; /* Load OEM cursor/icon */
959 /* Normalize hInstance (must be uniquely represented for icon cache) */
961 if (!HIWORD( hInstance ))
962 hInstance = HINSTANCE_32(GetExePtr( HINSTANCE_16(hInstance) ));
964 /* Get directory resource ID */
966 if (!(hRsrc = FindResourceW( hInstance, name,
967 (LPWSTR)(fCursor ? RT_GROUP_CURSOR : RT_GROUP_ICON) )))
968 return 0;
969 hGroupRsrc = hRsrc;
971 /* Find the best entry in the directory */
973 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
974 if (!(dir = (CURSORICONDIR*)LockResource( handle ))) return 0;
975 if (fCursor)
976 dirEntry = CURSORICON_FindBestCursorRes( dir, width, height, 1);
977 else
978 dirEntry = CURSORICON_FindBestIconRes( dir, width, height, colors );
979 if (!dirEntry) return 0;
980 wResId = dirEntry->wResId;
981 dwBytesInRes = dirEntry->dwBytesInRes;
982 FreeResource( handle );
984 /* Load the resource */
986 if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
987 (LPWSTR)(fCursor ? RT_CURSOR : RT_ICON) ))) return 0;
989 /* If shared icon, check whether it was already loaded */
990 if ( (loadflags & LR_SHARED)
991 && (hIcon = CURSORICON_FindSharedIcon( hInstance, hRsrc ) ) != 0 )
992 return hIcon;
994 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
995 bits = (LPBYTE)LockResource( handle );
996 hIcon = CreateIconFromResourceEx( bits, dwBytesInRes,
997 !fCursor, 0x00030000, width, height, loadflags);
998 FreeResource( handle );
1000 /* If shared icon, add to icon cache */
1002 if ( hIcon && (loadflags & LR_SHARED) )
1003 CURSORICON_AddSharedIcon( hInstance, hRsrc, hGroupRsrc, hIcon );
1005 return hIcon;
1008 /***********************************************************************
1009 * CURSORICON_Copy
1011 * Make a copy of a cursor or icon.
1013 static HICON CURSORICON_Copy( HINSTANCE16 hInst16, HICON hIcon )
1015 char *ptrOld, *ptrNew;
1016 int size;
1017 HICON16 hOld = HICON_16(hIcon);
1018 HICON16 hNew;
1020 if (!(ptrOld = (char *)GlobalLock16( hOld ))) return 0;
1021 if (hInst16 && !(hInst16 = GetExePtr( hInst16 ))) return 0;
1022 size = GlobalSize16( hOld );
1023 hNew = GlobalAlloc16( GMEM_MOVEABLE, size );
1024 FarSetOwner16( hNew, hInst16 );
1025 ptrNew = (char *)GlobalLock16( hNew );
1026 memcpy( ptrNew, ptrOld, size );
1027 GlobalUnlock16( hOld );
1028 GlobalUnlock16( hNew );
1029 return HICON_32(hNew);
1032 /*************************************************************************
1033 * CURSORICON_ExtCopy
1035 * Copies an Image from the Cache if LR_COPYFROMRESOURCE is specified
1037 * PARAMS
1038 * Handle [I] handle to an Image
1039 * nType [I] Type of Handle (IMAGE_CURSOR | IMAGE_ICON)
1040 * iDesiredCX [I] The Desired width of the Image
1041 * iDesiredCY [I] The desired height of the Image
1042 * nFlags [I] The flags from CopyImage
1044 * RETURNS
1045 * Success: The new handle of the Image
1047 * NOTES
1048 * LR_COPYDELETEORG and LR_MONOCHROME are currently not implemented.
1049 * LR_MONOCHROME should be implemented by CreateIconFromResourceEx.
1050 * LR_COPYFROMRESOURCE will only work if the Image is in the Cache.
1055 static HICON CURSORICON_ExtCopy(HICON hIcon, UINT nType,
1056 INT iDesiredCX, INT iDesiredCY,
1057 UINT nFlags)
1059 HICON hNew=0;
1061 TRACE_(icon)("hIcon %p, nType %u, iDesiredCX %i, iDesiredCY %i, nFlags %u\n",
1062 hIcon, nType, iDesiredCX, iDesiredCY, nFlags);
1064 if(hIcon == 0)
1066 return 0;
1069 /* Best Fit or Monochrome */
1070 if( (nFlags & LR_COPYFROMRESOURCE
1071 && (iDesiredCX > 0 || iDesiredCY > 0))
1072 || nFlags & LR_MONOCHROME)
1074 ICONCACHE* pIconCache = CURSORICON_FindCache(hIcon);
1076 /* Not Found in Cache, then do a straight copy
1078 if(pIconCache == NULL)
1080 hNew = CURSORICON_Copy(0, hIcon);
1081 if(nFlags & LR_COPYFROMRESOURCE)
1083 TRACE_(icon)("LR_COPYFROMRESOURCE: Failed to load from cache\n");
1086 else
1088 int iTargetCY = iDesiredCY, iTargetCX = iDesiredCX;
1089 LPBYTE pBits;
1090 HANDLE hMem;
1091 HRSRC hRsrc;
1092 DWORD dwBytesInRes;
1093 WORD wResId;
1094 CURSORICONDIR *pDir;
1095 CURSORICONDIRENTRY *pDirEntry;
1096 BOOL bIsIcon = (nType == IMAGE_ICON);
1098 /* Completing iDesiredCX CY for Monochrome Bitmaps if needed
1100 if(((nFlags & LR_MONOCHROME) && !(nFlags & LR_COPYFROMRESOURCE))
1101 || (iDesiredCX == 0 && iDesiredCY == 0))
1103 iDesiredCY = GetSystemMetrics(bIsIcon ?
1104 SM_CYICON : SM_CYCURSOR);
1105 iDesiredCX = GetSystemMetrics(bIsIcon ?
1106 SM_CXICON : SM_CXCURSOR);
1109 /* Retrieve the CURSORICONDIRENTRY
1111 if (!(hMem = LoadResource( pIconCache->hModule ,
1112 pIconCache->hGroupRsrc)))
1114 return 0;
1116 if (!(pDir = (CURSORICONDIR*)LockResource( hMem )))
1118 return 0;
1121 /* Find Best Fit
1123 if(bIsIcon)
1125 pDirEntry = CURSORICON_FindBestIconRes(
1126 pDir, iDesiredCX, iDesiredCY, 256 );
1128 else
1130 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursorRes(
1131 pDir, iDesiredCX, iDesiredCY, 1);
1134 wResId = pDirEntry->wResId;
1135 dwBytesInRes = pDirEntry->dwBytesInRes;
1136 FreeResource(hMem);
1138 TRACE_(icon)("ResID %u, BytesInRes %u, Width %d, Height %d DX %d, DY %d\n",
1139 wResId, dwBytesInRes, pDirEntry->ResInfo.icon.bWidth,
1140 pDirEntry->ResInfo.icon.bHeight, iDesiredCX, iDesiredCY);
1142 /* Get the Best Fit
1144 if (!(hRsrc = FindResourceW(pIconCache->hModule ,
1145 MAKEINTRESOURCEW(wResId), (LPWSTR)(bIsIcon ? RT_ICON : RT_CURSOR))))
1147 return 0;
1149 if (!(hMem = LoadResource( pIconCache->hModule , hRsrc )))
1151 return 0;
1154 pBits = (LPBYTE)LockResource( hMem );
1156 if(nFlags & LR_DEFAULTSIZE)
1158 iTargetCY = GetSystemMetrics(SM_CYICON);
1159 iTargetCX = GetSystemMetrics(SM_CXICON);
1162 /* Create a New Icon with the proper dimension
1164 hNew = CreateIconFromResourceEx( pBits, dwBytesInRes,
1165 bIsIcon, 0x00030000, iTargetCX, iTargetCY, nFlags);
1166 FreeResource(hMem);
1169 else hNew = CURSORICON_Copy(0, hIcon);
1170 return hNew;
1174 /***********************************************************************
1175 * CreateCursor (USER32.@)
1177 HCURSOR WINAPI CreateCursor( HINSTANCE hInstance,
1178 INT xHotSpot, INT yHotSpot,
1179 INT nWidth, INT nHeight,
1180 LPCVOID lpANDbits, LPCVOID lpXORbits )
1182 CURSORICONINFO info;
1184 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1185 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1187 info.ptHotSpot.x = xHotSpot;
1188 info.ptHotSpot.y = yHotSpot;
1189 info.nWidth = nWidth;
1190 info.nHeight = nHeight;
1191 info.nWidthBytes = 0;
1192 info.bPlanes = 1;
1193 info.bBitsPerPixel = 1;
1195 return HICON_32(CreateCursorIconIndirect16(0, &info, lpANDbits, lpXORbits));
1199 /***********************************************************************
1200 * CreateIcon (USER.407)
1202 HICON16 WINAPI CreateIcon16( HINSTANCE16 hInstance, INT16 nWidth,
1203 INT16 nHeight, BYTE bPlanes, BYTE bBitsPixel,
1204 LPCVOID lpANDbits, LPCVOID lpXORbits )
1206 CURSORICONINFO info;
1208 TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1209 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1211 info.ptHotSpot.x = ICON_HOTSPOT;
1212 info.ptHotSpot.y = ICON_HOTSPOT;
1213 info.nWidth = nWidth;
1214 info.nHeight = nHeight;
1215 info.nWidthBytes = 0;
1216 info.bPlanes = bPlanes;
1217 info.bBitsPerPixel = bBitsPixel;
1219 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1223 /***********************************************************************
1224 * CreateIcon (USER32.@)
1226 * Creates an icon based on the specified bitmaps. The bitmaps must be
1227 * provided in a device dependent format and will be resized to
1228 * (SM_CXICON,SM_CYICON) and depth converted to match the screen's color
1229 * depth. The provided bitmaps must be top-down bitmaps.
1230 * Although Windows does not support 15bpp(*) this API must support it
1231 * for Winelib applications.
1233 * (*) Windows does not support 15bpp but it supports the 555 RGB 16bpp
1234 * format!
1236 * RETURNS
1237 * Success: handle to an icon
1238 * Failure: NULL
1240 * FIXME: Do we need to resize the bitmaps?
1242 HICON WINAPI CreateIcon(
1243 HINSTANCE hInstance, /* [in] the application's hInstance */
1244 INT nWidth, /* [in] the width of the provided bitmaps */
1245 INT nHeight, /* [in] the height of the provided bitmaps */
1246 BYTE bPlanes, /* [in] the number of planes in the provided bitmaps */
1247 BYTE bBitsPixel, /* [in] the number of bits per pixel of the lpXORbits bitmap */
1248 LPCVOID lpANDbits, /* [in] a monochrome bitmap representing the icon's mask */
1249 LPCVOID lpXORbits) /* [in] the icon's 'color' bitmap */
1251 ICONINFO iinfo;
1252 HICON hIcon;
1254 TRACE_(icon)("%dx%d, planes %d, bpp %d, xor %p, and %p\n",
1255 nWidth, nHeight, bPlanes, bBitsPixel, lpXORbits, lpANDbits);
1257 iinfo.fIcon = TRUE;
1258 iinfo.xHotspot = ICON_HOTSPOT;
1259 iinfo.yHotspot = ICON_HOTSPOT;
1260 iinfo.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpANDbits );
1261 iinfo.hbmColor = CreateBitmap( nWidth, nHeight, bPlanes, bBitsPixel, lpXORbits );
1263 hIcon = CreateIconIndirect( &iinfo );
1265 DeleteObject( iinfo.hbmMask );
1266 DeleteObject( iinfo.hbmColor );
1268 return hIcon;
1272 /***********************************************************************
1273 * CreateCursorIconIndirect (USER.408)
1275 HGLOBAL16 WINAPI CreateCursorIconIndirect16( HINSTANCE16 hInstance,
1276 CURSORICONINFO *info,
1277 LPCVOID lpANDbits,
1278 LPCVOID lpXORbits )
1280 HGLOBAL16 handle;
1281 char *ptr;
1282 int sizeAnd, sizeXor;
1284 hInstance = GetExePtr( hInstance ); /* Make it a module handle */
1285 if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
1286 info->nWidthBytes = get_bitmap_width_bytes(info->nWidth,info->bBitsPerPixel);
1287 sizeXor = info->nHeight * info->nWidthBytes;
1288 sizeAnd = info->nHeight * get_bitmap_width_bytes( info->nWidth, 1 );
1289 if (!(handle = GlobalAlloc16( GMEM_MOVEABLE,
1290 sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
1291 return 0;
1292 FarSetOwner16( handle, hInstance );
1293 ptr = (char *)GlobalLock16( handle );
1294 memcpy( ptr, info, sizeof(*info) );
1295 memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
1296 memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
1297 GlobalUnlock16( handle );
1298 return handle;
1302 /***********************************************************************
1303 * CopyIcon (USER.368)
1305 HICON16 WINAPI CopyIcon16( HINSTANCE16 hInstance, HICON16 hIcon )
1307 TRACE_(icon)("%04x %04x\n", hInstance, hIcon );
1308 return HICON_16(CURSORICON_Copy(hInstance, HICON_32(hIcon)));
1312 /***********************************************************************
1313 * CopyIcon (USER32.@)
1315 HICON WINAPI CopyIcon( HICON hIcon )
1317 TRACE_(icon)("%p\n", hIcon );
1318 return CURSORICON_Copy( 0, hIcon );
1322 /***********************************************************************
1323 * CopyCursor (USER.369)
1325 HCURSOR16 WINAPI CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
1327 TRACE_(cursor)("%04x %04x\n", hInstance, hCursor );
1328 return HICON_16(CURSORICON_Copy(hInstance, HCURSOR_32(hCursor)));
1331 /**********************************************************************
1332 * DestroyIcon32 (USER.610)
1334 * This routine is actually exported from Win95 USER under the name
1335 * DestroyIcon32 ... The behaviour implemented here should mimic
1336 * the Win95 one exactly, especially the return values, which
1337 * depend on the setting of various flags.
1339 WORD WINAPI DestroyIcon32( HGLOBAL16 handle, UINT16 flags )
1341 WORD retv;
1343 TRACE_(icon)("(%04x, %04x)\n", handle, flags );
1345 /* Check whether destroying active cursor */
1347 if ( get_user_thread_info()->cursor == HICON_32(handle) )
1349 WARN_(cursor)("Destroying active cursor!\n" );
1350 SetCursor( 0 );
1353 /* Try shared cursor/icon first */
1355 if ( !(flags & CID_NONSHARED) )
1357 INT count = CURSORICON_DelSharedIcon(HICON_32(handle));
1359 if ( count != -1 )
1360 return (flags & CID_WIN32)? TRUE : (count == 0);
1362 /* FIXME: OEM cursors/icons should be recognized */
1365 /* Now assume non-shared cursor/icon */
1367 retv = GlobalFree16( handle );
1368 return (flags & CID_RESOURCE)? retv : TRUE;
1371 /***********************************************************************
1372 * DestroyIcon (USER32.@)
1374 BOOL WINAPI DestroyIcon( HICON hIcon )
1376 return DestroyIcon32(HICON_16(hIcon), CID_WIN32);
1380 /***********************************************************************
1381 * DestroyCursor (USER32.@)
1383 BOOL WINAPI DestroyCursor( HCURSOR hCursor )
1385 return DestroyIcon32(HCURSOR_16(hCursor), CID_WIN32);
1389 /***********************************************************************
1390 * DrawIcon (USER32.@)
1392 BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
1394 CURSORICONINFO *ptr;
1395 HDC hMemDC;
1396 HBITMAP hXorBits, hAndBits;
1397 COLORREF oldFg, oldBg;
1399 TRACE("%p, (%d,%d), %p\n", hdc, x, y, hIcon);
1401 if (!(ptr = (CURSORICONINFO *)GlobalLock16(HICON_16(hIcon)))) return FALSE;
1402 if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
1403 hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1,
1404 (char *)(ptr+1) );
1405 hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
1406 ptr->bBitsPerPixel, (char *)(ptr + 1)
1407 + ptr->nHeight * get_bitmap_width_bytes(ptr->nWidth,1) );
1408 oldFg = SetTextColor( hdc, RGB(0,0,0) );
1409 oldBg = SetBkColor( hdc, RGB(255,255,255) );
1411 if (hXorBits && hAndBits)
1413 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1414 BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
1415 SelectObject( hMemDC, hXorBits );
1416 BitBlt(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
1417 SelectObject( hMemDC, hBitTemp );
1419 DeleteDC( hMemDC );
1420 if (hXorBits) DeleteObject( hXorBits );
1421 if (hAndBits) DeleteObject( hAndBits );
1422 GlobalUnlock16(HICON_16(hIcon));
1423 SetTextColor( hdc, oldFg );
1424 SetBkColor( hdc, oldBg );
1425 return TRUE;
1428 /***********************************************************************
1429 * DumpIcon (USER.459)
1431 DWORD WINAPI DumpIcon16( SEGPTR pInfo, WORD *lpLen,
1432 SEGPTR *lpXorBits, SEGPTR *lpAndBits )
1434 CURSORICONINFO *info = MapSL( pInfo );
1435 int sizeAnd, sizeXor;
1437 if (!info) return 0;
1438 sizeXor = info->nHeight * info->nWidthBytes;
1439 sizeAnd = info->nHeight * get_bitmap_width_bytes( info->nWidth, 1 );
1440 if (lpAndBits) *lpAndBits = pInfo + sizeof(CURSORICONINFO);
1441 if (lpXorBits) *lpXorBits = pInfo + sizeof(CURSORICONINFO) + sizeAnd;
1442 if (lpLen) *lpLen = sizeof(CURSORICONINFO) + sizeAnd + sizeXor;
1443 return MAKELONG( sizeXor, sizeXor );
1447 /***********************************************************************
1448 * SetCursor (USER32.@)
1450 * Set the cursor shape.
1452 * RETURNS
1453 * A handle to the previous cursor shape.
1455 HCURSOR WINAPI SetCursor( HCURSOR hCursor /* [in] Handle of cursor to show */ )
1457 struct user_thread_info *thread_info = get_user_thread_info();
1458 HCURSOR hOldCursor;
1460 if (hCursor == thread_info->cursor) return hCursor; /* No change */
1461 TRACE("%p\n", hCursor);
1462 hOldCursor = thread_info->cursor;
1463 thread_info->cursor = hCursor;
1464 /* Change the cursor shape only if it is visible */
1465 if (thread_info->cursor_count >= 0)
1467 USER_Driver->pSetCursor( (CURSORICONINFO*)GlobalLock16(HCURSOR_16(hCursor)) );
1468 GlobalUnlock16(HCURSOR_16(hCursor));
1470 return hOldCursor;
1473 /***********************************************************************
1474 * ShowCursor (USER32.@)
1476 INT WINAPI ShowCursor( BOOL bShow )
1478 struct user_thread_info *thread_info = get_user_thread_info();
1480 TRACE("%d, count=%d\n", bShow, thread_info->cursor_count );
1482 if (bShow)
1484 if (++thread_info->cursor_count == 0) /* Show it */
1486 USER_Driver->pSetCursor((CURSORICONINFO*)GlobalLock16(HCURSOR_16(thread_info->cursor)));
1487 GlobalUnlock16(HCURSOR_16(thread_info->cursor));
1490 else
1492 if (--thread_info->cursor_count == -1) /* Hide it */
1493 USER_Driver->pSetCursor( NULL );
1495 return thread_info->cursor_count;
1498 /***********************************************************************
1499 * GetCursor (USER32.@)
1501 HCURSOR WINAPI GetCursor(void)
1503 return get_user_thread_info()->cursor;
1507 /***********************************************************************
1508 * ClipCursor (USER32.@)
1510 BOOL WINAPI ClipCursor( const RECT *rect )
1512 RECT virt;
1514 SetRect( &virt, 0, 0, GetSystemMetrics( SM_CXVIRTUALSCREEN ),
1515 GetSystemMetrics( SM_CYVIRTUALSCREEN ) );
1516 OffsetRect( &virt, GetSystemMetrics( SM_XVIRTUALSCREEN ),
1517 GetSystemMetrics( SM_YVIRTUALSCREEN ) );
1519 TRACE( "Clipping to: %s was: %s screen: %s\n", wine_dbgstr_rect(rect),
1520 wine_dbgstr_rect(&CURSOR_ClipRect), wine_dbgstr_rect(&virt) );
1522 if (!IntersectRect( &CURSOR_ClipRect, &virt, rect ))
1523 CURSOR_ClipRect = virt;
1525 USER_Driver->pClipCursor( rect );
1526 return TRUE;
1530 /***********************************************************************
1531 * GetClipCursor (USER32.@)
1533 BOOL WINAPI GetClipCursor( RECT *rect )
1535 /* If this is first time - initialize the rect */
1536 if (IsRectEmpty( &CURSOR_ClipRect )) ClipCursor( NULL );
1538 return CopyRect( rect, &CURSOR_ClipRect );
1542 /***********************************************************************
1543 * SetSystemCursor (USER32.@)
1545 BOOL WINAPI SetSystemCursor(HCURSOR hcur, DWORD id)
1547 FIXME("(%p,%08x),stub!\n", hcur, id);
1548 return TRUE;
1552 /**********************************************************************
1553 * LookupIconIdFromDirectoryEx (USER.364)
1555 * FIXME: exact parameter sizes
1557 INT16 WINAPI LookupIconIdFromDirectoryEx16( LPBYTE dir, BOOL16 bIcon,
1558 INT16 width, INT16 height, UINT16 cFlag )
1560 return LookupIconIdFromDirectoryEx( dir, bIcon, width, height, cFlag );
1563 /**********************************************************************
1564 * LookupIconIdFromDirectoryEx (USER32.@)
1566 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE xdir, BOOL bIcon,
1567 INT width, INT height, UINT cFlag )
1569 CURSORICONDIR *dir = (CURSORICONDIR*)xdir;
1570 UINT retVal = 0;
1571 if( dir && !dir->idReserved && (dir->idType & 3) )
1573 CURSORICONDIRENTRY* entry;
1574 HDC hdc;
1575 UINT palEnts;
1576 int colors;
1577 hdc = GetDC(0);
1578 palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
1579 if (palEnts == 0)
1580 palEnts = 256;
1581 colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
1583 ReleaseDC(0, hdc);
1585 if( bIcon )
1586 entry = CURSORICON_FindBestIconRes( dir, width, height, colors );
1587 else
1588 entry = CURSORICON_FindBestCursorRes( dir, width, height, 1);
1590 if( entry ) retVal = entry->wResId;
1592 else WARN_(cursor)("invalid resource directory\n");
1593 return retVal;
1596 /**********************************************************************
1597 * LookupIconIdFromDirectory (USER.?)
1599 INT16 WINAPI LookupIconIdFromDirectory16( LPBYTE dir, BOOL16 bIcon )
1601 return LookupIconIdFromDirectoryEx16( dir, bIcon,
1602 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1603 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1606 /**********************************************************************
1607 * LookupIconIdFromDirectory (USER32.@)
1609 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1611 return LookupIconIdFromDirectoryEx( dir, bIcon,
1612 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1613 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1616 /**********************************************************************
1617 * GetIconID (USER.455)
1619 WORD WINAPI GetIconID16( HGLOBAL16 hResource, DWORD resType )
1621 LPBYTE lpDir = (LPBYTE)GlobalLock16(hResource);
1623 TRACE_(cursor)("hRes=%04x, entries=%i\n",
1624 hResource, lpDir ? ((CURSORICONDIR*)lpDir)->idCount : 0);
1626 switch(resType)
1628 case RT_CURSOR:
1629 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, FALSE,
1630 GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1631 case RT_ICON:
1632 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, TRUE,
1633 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0 );
1634 default:
1635 WARN_(cursor)("invalid res type %d\n", resType );
1637 return 0;
1640 /**********************************************************************
1641 * LoadCursorIconHandler (USER.336)
1643 * Supposed to load resources of Windows 2.x applications.
1645 HGLOBAL16 WINAPI LoadCursorIconHandler16( HGLOBAL16 hResource, HMODULE16 hModule, HRSRC16 hRsrc )
1647 FIXME_(cursor)("(%04x,%04x,%04x): old 2.x resources are not supported!\n",
1648 hResource, hModule, hRsrc);
1649 return (HGLOBAL16)0;
1652 /**********************************************************************
1653 * LoadIconHandler (USER.456)
1655 HICON16 WINAPI LoadIconHandler16( HGLOBAL16 hResource, BOOL16 bNew )
1657 LPBYTE bits = (LPBYTE)LockResource16( hResource );
1659 TRACE_(cursor)("hRes=%04x\n",hResource);
1661 return HICON_16(CreateIconFromResourceEx( bits, 0, TRUE,
1662 bNew ? 0x00030000 : 0x00020000, 0, 0, LR_DEFAULTCOLOR));
1665 /***********************************************************************
1666 * LoadCursorW (USER32.@)
1668 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
1670 TRACE("%p, %s\n", hInstance, debugstr_w(name));
1672 return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0,
1673 LR_SHARED | LR_DEFAULTSIZE );
1676 /***********************************************************************
1677 * LoadCursorA (USER32.@)
1679 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
1681 TRACE("%p, %s\n", hInstance, debugstr_a(name));
1683 return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0,
1684 LR_SHARED | LR_DEFAULTSIZE );
1687 /***********************************************************************
1688 * LoadCursorFromFileW (USER32.@)
1690 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
1692 TRACE("%s\n", debugstr_w(name));
1694 return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0,
1695 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1698 /***********************************************************************
1699 * LoadCursorFromFileA (USER32.@)
1701 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
1703 TRACE("%s\n", debugstr_a(name));
1705 return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0,
1706 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1709 /***********************************************************************
1710 * LoadIconW (USER32.@)
1712 HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
1714 TRACE("%p, %s\n", hInstance, debugstr_w(name));
1716 return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0,
1717 LR_SHARED | LR_DEFAULTSIZE );
1720 /***********************************************************************
1721 * LoadIconA (USER32.@)
1723 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
1725 TRACE("%p, %s\n", hInstance, debugstr_a(name));
1727 return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0,
1728 LR_SHARED | LR_DEFAULTSIZE );
1731 /**********************************************************************
1732 * GetIconInfo (USER32.@)
1734 BOOL WINAPI GetIconInfo(HICON hIcon, PICONINFO iconinfo)
1736 CURSORICONINFO *ciconinfo;
1737 INT height;
1739 ciconinfo = GlobalLock16(HICON_16(hIcon));
1740 if (!ciconinfo)
1741 return FALSE;
1743 TRACE("%p => %dx%d, %d bpp\n", hIcon,
1744 ciconinfo->nWidth, ciconinfo->nHeight, ciconinfo->bBitsPerPixel);
1746 if ( (ciconinfo->ptHotSpot.x == ICON_HOTSPOT) &&
1747 (ciconinfo->ptHotSpot.y == ICON_HOTSPOT) )
1749 iconinfo->fIcon = TRUE;
1750 iconinfo->xHotspot = ciconinfo->nWidth / 2;
1751 iconinfo->yHotspot = ciconinfo->nHeight / 2;
1753 else
1755 iconinfo->fIcon = FALSE;
1756 iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
1757 iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
1760 height = ciconinfo->nHeight;
1762 if (ciconinfo->bBitsPerPixel > 1)
1764 iconinfo->hbmColor = CreateBitmap( ciconinfo->nWidth, ciconinfo->nHeight,
1765 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
1766 (char *)(ciconinfo + 1)
1767 + ciconinfo->nHeight *
1768 get_bitmap_width_bytes (ciconinfo->nWidth,1) );
1770 else
1772 iconinfo->hbmColor = 0;
1773 height *= 2;
1776 iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, height,
1777 1, 1, (char *)(ciconinfo + 1));
1779 GlobalUnlock16(HICON_16(hIcon));
1781 return TRUE;
1784 /**********************************************************************
1785 * CreateIconIndirect (USER32.@)
1787 HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
1789 BITMAP bmpXor,bmpAnd;
1790 HICON16 hObj;
1791 int sizeXor,sizeAnd;
1793 TRACE("color %p, mask %p, hotspot %ux%u, fIcon %d\n",
1794 iconinfo->hbmColor, iconinfo->hbmMask,
1795 iconinfo->xHotspot, iconinfo->yHotspot, iconinfo->fIcon);
1797 if (!iconinfo->hbmMask) return 0;
1799 if (iconinfo->hbmColor)
1801 GetObjectW( iconinfo->hbmColor, sizeof(bmpXor), &bmpXor );
1802 TRACE("color: width %d, height %d, width bytes %d, planes %u, bpp %u\n",
1803 bmpXor.bmWidth, bmpXor.bmHeight, bmpXor.bmWidthBytes,
1804 bmpXor.bmPlanes, bmpXor.bmBitsPixel);
1806 GetObjectW( iconinfo->hbmMask, sizeof(bmpAnd), &bmpAnd );
1807 TRACE("mask: width %d, height %d, width bytes %d, planes %u, bpp %u\n",
1808 bmpAnd.bmWidth, bmpAnd.bmHeight, bmpAnd.bmWidthBytes,
1809 bmpAnd.bmPlanes, bmpAnd.bmBitsPixel);
1811 sizeXor = iconinfo->hbmColor ? (bmpXor.bmHeight * bmpXor.bmWidthBytes) : 0;
1812 sizeAnd = bmpAnd.bmHeight * get_bitmap_width_bytes(bmpAnd.bmWidth, 1);
1814 hObj = GlobalAlloc16( GMEM_MOVEABLE,
1815 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
1816 if (hObj)
1818 CURSORICONINFO *info;
1820 info = (CURSORICONINFO *)GlobalLock16( hObj );
1822 /* If we are creating an icon, the hotspot is unused */
1823 if (iconinfo->fIcon)
1825 info->ptHotSpot.x = ICON_HOTSPOT;
1826 info->ptHotSpot.y = ICON_HOTSPOT;
1828 else
1830 info->ptHotSpot.x = iconinfo->xHotspot;
1831 info->ptHotSpot.y = iconinfo->yHotspot;
1834 if (iconinfo->hbmColor)
1836 info->nWidth = bmpXor.bmWidth;
1837 info->nHeight = bmpXor.bmHeight;
1838 info->nWidthBytes = bmpXor.bmWidthBytes;
1839 info->bPlanes = bmpXor.bmPlanes;
1840 info->bBitsPerPixel = bmpXor.bmBitsPixel;
1842 else
1844 info->nWidth = bmpAnd.bmWidth;
1845 info->nHeight = bmpAnd.bmHeight / 2;
1846 info->nWidthBytes = get_bitmap_width_bytes(bmpAnd.bmWidth, 1);
1847 info->bPlanes = 1;
1848 info->bBitsPerPixel = 1;
1851 /* Transfer the bitmap bits to the CURSORICONINFO structure */
1853 /* Some apps pass a color bitmap as a mask, convert it to b/w */
1854 if (bmpAnd.bmBitsPixel == 1)
1856 GetBitmapBits( iconinfo->hbmMask, sizeAnd, (char*)(info + 1) );
1858 else
1860 HDC hdc, hdc_mem;
1861 HBITMAP hbmp_old, hbmp_mem_old, hbmp_mono;
1863 hdc = GetDC( 0 );
1864 hdc_mem = CreateCompatibleDC( hdc );
1866 hbmp_mono = CreateBitmap( bmpAnd.bmWidth, bmpAnd.bmHeight, 1, 1, NULL );
1868 hbmp_old = SelectObject( hdc, iconinfo->hbmMask );
1869 hbmp_mem_old = SelectObject( hdc_mem, hbmp_mono );
1871 BitBlt( hdc_mem, 0, 0, bmpAnd.bmWidth, bmpAnd.bmHeight, hdc, 0, 0, SRCCOPY );
1873 SelectObject( hdc, hbmp_old );
1874 SelectObject( hdc_mem, hbmp_mem_old );
1876 DeleteDC( hdc_mem );
1877 ReleaseDC( 0, hdc );
1879 GetBitmapBits( hbmp_mono, sizeAnd, (char*)(info + 1) );
1880 DeleteObject( hbmp_mono );
1882 if (iconinfo->hbmColor) GetBitmapBits( iconinfo->hbmColor, sizeXor, (char*)(info + 1) + sizeAnd );
1883 GlobalUnlock16( hObj );
1885 return HICON_32(hObj);
1888 /******************************************************************************
1889 * DrawIconEx (USER32.@) Draws an icon or cursor on device context
1891 * NOTES
1892 * Why is this using SM_CXICON instead of SM_CXCURSOR?
1894 * PARAMS
1895 * hdc [I] Handle to device context
1896 * x0 [I] X coordinate of upper left corner
1897 * y0 [I] Y coordinate of upper left corner
1898 * hIcon [I] Handle to icon to draw
1899 * cxWidth [I] Width of icon
1900 * cyWidth [I] Height of icon
1901 * istep [I] Index of frame in animated cursor
1902 * hbr [I] Handle to background brush
1903 * flags [I] Icon-drawing flags
1905 * RETURNS
1906 * Success: TRUE
1907 * Failure: FALSE
1909 BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
1910 INT cxWidth, INT cyWidth, UINT istep,
1911 HBRUSH hbr, UINT flags )
1913 CURSORICONINFO *ptr = (CURSORICONINFO *)GlobalLock16(HICON_16(hIcon));
1914 HDC hDC_off = 0, hMemDC;
1915 BOOL result = FALSE, DoOffscreen;
1916 HBITMAP hB_off = 0, hOld = 0;
1918 if (!ptr) return FALSE;
1919 TRACE_(icon)("(hdc=%p,pos=%d.%d,hicon=%p,extend=%d.%d,istep=%d,br=%p,flags=0x%08x)\n",
1920 hdc,x0,y0,hIcon,cxWidth,cyWidth,istep,hbr,flags );
1922 hMemDC = CreateCompatibleDC (hdc);
1923 if (istep)
1924 FIXME_(icon)("Ignoring istep=%d\n", istep);
1925 if (flags & DI_COMPAT)
1926 FIXME_(icon)("Ignoring flag DI_COMPAT\n");
1928 if (!flags) {
1929 FIXME_(icon)("no flags set? setting to DI_NORMAL\n");
1930 flags = DI_NORMAL;
1933 /* Calculate the size of the destination image. */
1934 if (cxWidth == 0)
1936 if (flags & DI_DEFAULTSIZE)
1937 cxWidth = GetSystemMetrics (SM_CXICON);
1938 else
1939 cxWidth = ptr->nWidth;
1941 if (cyWidth == 0)
1943 if (flags & DI_DEFAULTSIZE)
1944 cyWidth = GetSystemMetrics (SM_CYICON);
1945 else
1946 cyWidth = ptr->nHeight;
1949 DoOffscreen = (GetObjectType( hbr ) == OBJ_BRUSH);
1951 if (DoOffscreen) {
1952 RECT r;
1954 r.left = 0;
1955 r.top = 0;
1956 r.right = cxWidth;
1957 r.bottom = cxWidth;
1959 hDC_off = CreateCompatibleDC(hdc);
1960 hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth);
1961 if (hDC_off && hB_off) {
1962 hOld = SelectObject(hDC_off, hB_off);
1963 FillRect(hDC_off, &r, hbr);
1967 if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
1969 HBITMAP hXorBits, hAndBits;
1970 COLORREF oldFg, oldBg;
1971 INT nStretchMode;
1973 nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
1975 hXorBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1976 ptr->bPlanes, ptr->bBitsPerPixel,
1977 (char *)(ptr + 1)
1978 + ptr->nHeight *
1979 get_bitmap_width_bytes(ptr->nWidth,1) );
1980 hAndBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1981 1, 1, (char *)(ptr+1) );
1982 oldFg = SetTextColor( hdc, RGB(0,0,0) );
1983 oldBg = SetBkColor( hdc, RGB(255,255,255) );
1985 if (hXorBits && hAndBits)
1987 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1988 if (flags & DI_MASK)
1990 if (DoOffscreen)
1991 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1992 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1993 else
1994 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
1995 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1997 SelectObject( hMemDC, hXorBits );
1998 if (flags & DI_IMAGE)
2000 if (DoOffscreen)
2001 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
2002 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
2003 else
2004 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
2005 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
2007 SelectObject( hMemDC, hBitTemp );
2008 result = TRUE;
2011 SetTextColor( hdc, oldFg );
2012 SetBkColor( hdc, oldBg );
2013 if (hXorBits) DeleteObject( hXorBits );
2014 if (hAndBits) DeleteObject( hAndBits );
2015 SetStretchBltMode (hdc, nStretchMode);
2016 if (DoOffscreen) {
2017 BitBlt(hdc, x0, y0, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
2018 SelectObject(hDC_off, hOld);
2021 if (hMemDC) DeleteDC( hMemDC );
2022 if (hDC_off) DeleteDC(hDC_off);
2023 if (hB_off) DeleteObject(hB_off);
2024 GlobalUnlock16(HICON_16(hIcon));
2025 return result;
2028 /***********************************************************************
2029 * DIB_FixColorsToLoadflags
2031 * Change color table entries when LR_LOADTRANSPARENT or LR_LOADMAP3DCOLORS
2032 * are in loadflags
2034 static void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags, BYTE pix)
2036 int colors;
2037 COLORREF c_W, c_S, c_F, c_L, c_C;
2038 int incr,i;
2039 RGBQUAD *ptr;
2040 int bitmap_type;
2041 LONG width;
2042 LONG height;
2043 WORD bpp;
2044 DWORD compr;
2046 if (((bitmap_type = DIB_GetBitmapInfo((BITMAPINFOHEADER*) bmi, &width, &height, &bpp, &compr)) == -1))
2048 WARN_(resource)("Invalid bitmap\n");
2049 return;
2052 if (bpp > 8) return;
2054 if (bitmap_type == 0) /* BITMAPCOREHEADER */
2056 incr = 3;
2057 colors = 1 << bpp;
2059 else
2061 incr = 4;
2062 colors = bmi->bmiHeader.biClrUsed;
2063 if (colors > 256) colors = 256;
2064 if (!colors && (bpp <= 8)) colors = 1 << bpp;
2067 c_W = GetSysColor(COLOR_WINDOW);
2068 c_S = GetSysColor(COLOR_3DSHADOW);
2069 c_F = GetSysColor(COLOR_3DFACE);
2070 c_L = GetSysColor(COLOR_3DLIGHT);
2072 if (loadflags & LR_LOADTRANSPARENT) {
2073 switch (bpp) {
2074 case 1: pix = pix >> 7; break;
2075 case 4: pix = pix >> 4; break;
2076 case 8: break;
2077 default:
2078 WARN_(resource)("(%d): Unsupported depth\n", bpp);
2079 return;
2081 if (pix >= colors) {
2082 WARN_(resource)("pixel has color index greater than biClrUsed!\n");
2083 return;
2085 if (loadflags & LR_LOADMAP3DCOLORS) c_W = c_F;
2086 ptr = (RGBQUAD*)((char*)bmi->bmiColors+pix*incr);
2087 ptr->rgbBlue = GetBValue(c_W);
2088 ptr->rgbGreen = GetGValue(c_W);
2089 ptr->rgbRed = GetRValue(c_W);
2091 if (loadflags & LR_LOADMAP3DCOLORS)
2092 for (i=0; i<colors; i++) {
2093 ptr = (RGBQUAD*)((char*)bmi->bmiColors+i*incr);
2094 c_C = RGB(ptr->rgbRed, ptr->rgbGreen, ptr->rgbBlue);
2095 if (c_C == RGB(128, 128, 128)) {
2096 ptr->rgbRed = GetRValue(c_S);
2097 ptr->rgbGreen = GetGValue(c_S);
2098 ptr->rgbBlue = GetBValue(c_S);
2099 } else if (c_C == RGB(192, 192, 192)) {
2100 ptr->rgbRed = GetRValue(c_F);
2101 ptr->rgbGreen = GetGValue(c_F);
2102 ptr->rgbBlue = GetBValue(c_F);
2103 } else if (c_C == RGB(223, 223, 223)) {
2104 ptr->rgbRed = GetRValue(c_L);
2105 ptr->rgbGreen = GetGValue(c_L);
2106 ptr->rgbBlue = GetBValue(c_L);
2112 /**********************************************************************
2113 * BITMAP_Load
2115 static HBITMAP BITMAP_Load( HINSTANCE instance, LPCWSTR name,
2116 INT desiredx, INT desiredy, UINT loadflags )
2118 HBITMAP hbitmap = 0, orig_bm;
2119 HRSRC hRsrc;
2120 HGLOBAL handle;
2121 char *ptr = NULL;
2122 BITMAPINFO *info, *fix_info = NULL, *scaled_info = NULL;
2123 int size;
2124 BYTE pix;
2125 char *bits;
2126 LONG width, height, new_width, new_height;
2127 WORD bpp_dummy;
2128 DWORD compr_dummy;
2129 INT bm_type;
2130 HDC screen_mem_dc = NULL;
2132 if (!(loadflags & LR_LOADFROMFILE))
2134 if (!instance)
2136 /* OEM bitmap: try to load the resource from user32.dll */
2137 instance = user32_module;
2140 if (!(hRsrc = FindResourceW( instance, name, (LPWSTR)RT_BITMAP ))) return 0;
2141 if (!(handle = LoadResource( instance, hRsrc ))) return 0;
2143 if ((info = (BITMAPINFO *)LockResource( handle )) == NULL) return 0;
2145 else
2147 if (!(ptr = map_fileW( name, NULL ))) return 0;
2148 info = (BITMAPINFO *)(ptr + sizeof(BITMAPFILEHEADER));
2151 size = bitmap_info_size(info, DIB_RGB_COLORS);
2152 fix_info = HeapAlloc(GetProcessHeap(), 0, size);
2153 scaled_info = HeapAlloc(GetProcessHeap(), 0, size);
2155 if (!fix_info || !scaled_info) goto end;
2156 memcpy(fix_info, info, size);
2158 pix = *((LPBYTE)info + size);
2159 DIB_FixColorsToLoadflags(fix_info, loadflags, pix);
2161 memcpy(scaled_info, fix_info, size);
2162 bm_type = DIB_GetBitmapInfo( &fix_info->bmiHeader, &width, &height,
2163 &bpp_dummy, &compr_dummy);
2164 if(desiredx != 0)
2165 new_width = desiredx;
2166 else
2167 new_width = width;
2169 if(desiredy != 0)
2170 new_height = height > 0 ? desiredy : -desiredy;
2171 else
2172 new_height = height;
2174 if(bm_type == 0)
2176 BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)&scaled_info->bmiHeader;
2177 core->bcWidth = new_width;
2178 core->bcHeight = new_height;
2180 else
2182 scaled_info->bmiHeader.biWidth = new_width;
2183 scaled_info->bmiHeader.biHeight = new_height;
2186 if (new_height < 0) new_height = -new_height;
2188 if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
2189 if (!(screen_mem_dc = CreateCompatibleDC( screen_dc ))) goto end;
2191 bits = (char *)info + size;
2193 if (loadflags & LR_CREATEDIBSECTION)
2195 scaled_info->bmiHeader.biCompression = 0; /* DIBSection can't be compressed */
2196 hbitmap = CreateDIBSection(screen_dc, scaled_info, DIB_RGB_COLORS, NULL, 0, 0);
2198 else
2200 if (is_dib_monochrome(fix_info))
2201 hbitmap = CreateBitmap(new_width, new_height, 1, 1, NULL);
2202 else
2203 hbitmap = CreateCompatibleBitmap(screen_dc, new_width, new_height);
2206 orig_bm = SelectObject(screen_mem_dc, hbitmap);
2207 StretchDIBits(screen_mem_dc, 0, 0, new_width, new_height, 0, 0, width, height, bits, fix_info, DIB_RGB_COLORS, SRCCOPY);
2208 SelectObject(screen_mem_dc, orig_bm);
2210 end:
2211 if (screen_mem_dc) DeleteDC(screen_mem_dc);
2212 HeapFree(GetProcessHeap(), 0, scaled_info);
2213 HeapFree(GetProcessHeap(), 0, fix_info);
2214 if (loadflags & LR_LOADFROMFILE) UnmapViewOfFile( ptr );
2216 return hbitmap;
2219 /**********************************************************************
2220 * LoadImageA (USER32.@)
2222 * See LoadImageW.
2224 HANDLE WINAPI LoadImageA( HINSTANCE hinst, LPCSTR name, UINT type,
2225 INT desiredx, INT desiredy, UINT loadflags)
2227 HANDLE res;
2228 LPWSTR u_name;
2230 if (!HIWORD(name))
2231 return LoadImageW(hinst, (LPCWSTR)name, type, desiredx, desiredy, loadflags);
2233 __TRY {
2234 DWORD len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
2235 u_name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2236 MultiByteToWideChar( CP_ACP, 0, name, -1, u_name, len );
2238 __EXCEPT_PAGE_FAULT {
2239 SetLastError( ERROR_INVALID_PARAMETER );
2240 return 0;
2242 __ENDTRY
2243 res = LoadImageW(hinst, u_name, type, desiredx, desiredy, loadflags);
2244 HeapFree(GetProcessHeap(), 0, u_name);
2245 return res;
2249 /******************************************************************************
2250 * LoadImageW (USER32.@) Loads an icon, cursor, or bitmap
2252 * PARAMS
2253 * hinst [I] Handle of instance that contains image
2254 * name [I] Name of image
2255 * type [I] Type of image
2256 * desiredx [I] Desired width
2257 * desiredy [I] Desired height
2258 * loadflags [I] Load flags
2260 * RETURNS
2261 * Success: Handle to newly loaded image
2262 * Failure: NULL
2264 * FIXME: Implementation lacks some features, see LR_ defines in winuser.h
2266 HANDLE WINAPI LoadImageW( HINSTANCE hinst, LPCWSTR name, UINT type,
2267 INT desiredx, INT desiredy, UINT loadflags )
2269 TRACE_(resource)("(%p,%s,%d,%d,%d,0x%08x)\n",
2270 hinst,debugstr_w(name),type,desiredx,desiredy,loadflags);
2272 if (loadflags & LR_DEFAULTSIZE) {
2273 if (type == IMAGE_ICON) {
2274 if (!desiredx) desiredx = GetSystemMetrics(SM_CXICON);
2275 if (!desiredy) desiredy = GetSystemMetrics(SM_CYICON);
2276 } else if (type == IMAGE_CURSOR) {
2277 if (!desiredx) desiredx = GetSystemMetrics(SM_CXCURSOR);
2278 if (!desiredy) desiredy = GetSystemMetrics(SM_CYCURSOR);
2281 if (loadflags & LR_LOADFROMFILE) loadflags &= ~LR_SHARED;
2282 switch (type) {
2283 case IMAGE_BITMAP:
2284 return BITMAP_Load( hinst, name, desiredx, desiredy, loadflags );
2286 case IMAGE_ICON:
2287 if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
2288 if (screen_dc)
2290 UINT palEnts = GetSystemPaletteEntries(screen_dc, 0, 0, NULL);
2291 if (palEnts == 0) palEnts = 256;
2292 return CURSORICON_Load(hinst, name, desiredx, desiredy,
2293 palEnts, FALSE, loadflags);
2295 break;
2297 case IMAGE_CURSOR:
2298 return CURSORICON_Load(hinst, name, desiredx, desiredy,
2299 1, TRUE, loadflags);
2301 return 0;
2304 /******************************************************************************
2305 * CopyImage (USER32.@) Creates new image and copies attributes to it
2307 * PARAMS
2308 * hnd [I] Handle to image to copy
2309 * type [I] Type of image to copy
2310 * desiredx [I] Desired width of new image
2311 * desiredy [I] Desired height of new image
2312 * flags [I] Copy flags
2314 * RETURNS
2315 * Success: Handle to newly created image
2316 * Failure: NULL
2318 * BUGS
2319 * Only Windows NT 4.0 supports the LR_COPYRETURNORG flag for bitmaps,
2320 * all other versions (95/2000/XP have been tested) ignore it.
2322 * NOTES
2323 * If LR_CREATEDIBSECTION is absent, the copy will be monochrome for
2324 * a monochrome source bitmap or if LR_MONOCHROME is present, otherwise
2325 * the copy will have the same depth as the screen.
2326 * The content of the image will only be copied if the bit depth of the
2327 * original image is compatible with the bit depth of the screen, or
2328 * if the source is a DIB section.
2329 * The LR_MONOCHROME flag is ignored if LR_CREATEDIBSECTION is present.
2331 HANDLE WINAPI CopyImage( HANDLE hnd, UINT type, INT desiredx,
2332 INT desiredy, UINT flags )
2334 TRACE("hnd=%p, type=%u, desiredx=%d, desiredy=%d, flags=%x\n",
2335 hnd, type, desiredx, desiredy, flags);
2337 switch (type)
2339 case IMAGE_BITMAP:
2341 HBITMAP res = NULL;
2342 DIBSECTION ds;
2343 int objSize;
2344 BITMAPINFO * bi;
2346 objSize = GetObjectW( hnd, sizeof(ds), &ds );
2347 if (!objSize) return 0;
2348 if ((desiredx < 0) || (desiredy < 0)) return 0;
2350 if (flags & LR_COPYFROMRESOURCE)
2352 FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
2355 if (desiredx == 0) desiredx = ds.dsBm.bmWidth;
2356 if (desiredy == 0) desiredy = ds.dsBm.bmHeight;
2358 /* Allocate memory for a BITMAPINFOHEADER structure and a
2359 color table. The maximum number of colors in a color table
2360 is 256 which corresponds to a bitmap with depth 8.
2361 Bitmaps with higher depths don't have color tables. */
2362 bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2363 if (!bi) return 0;
2365 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
2366 bi->bmiHeader.biPlanes = ds.dsBm.bmPlanes;
2367 bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
2368 bi->bmiHeader.biCompression = BI_RGB;
2370 if (flags & LR_CREATEDIBSECTION)
2372 /* Create a DIB section. LR_MONOCHROME is ignored */
2373 void * bits;
2374 HDC dc = CreateCompatibleDC(NULL);
2376 if (objSize == sizeof(DIBSECTION))
2378 /* The source bitmap is a DIB.
2379 Get its attributes to create an exact copy */
2380 memcpy(bi, &ds.dsBmih, sizeof(BITMAPINFOHEADER));
2383 /* Get the color table or the color masks */
2384 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
2386 bi->bmiHeader.biWidth = desiredx;
2387 bi->bmiHeader.biHeight = desiredy;
2388 bi->bmiHeader.biSizeImage = 0;
2390 res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
2391 DeleteDC(dc);
2393 else
2395 /* Create a device-dependent bitmap */
2397 BOOL monochrome = (flags & LR_MONOCHROME);
2399 if (objSize == sizeof(DIBSECTION))
2401 /* The source bitmap is a DIB section.
2402 Get its attributes */
2403 HDC dc = CreateCompatibleDC(NULL);
2404 bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
2405 bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
2406 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
2407 DeleteDC(dc);
2409 if (!monochrome && ds.dsBm.bmBitsPixel == 1)
2411 /* Look if the colors of the DIB are black and white */
2413 monochrome =
2414 (bi->bmiColors[0].rgbRed == 0xff
2415 && bi->bmiColors[0].rgbGreen == 0xff
2416 && bi->bmiColors[0].rgbBlue == 0xff
2417 && bi->bmiColors[0].rgbReserved == 0
2418 && bi->bmiColors[1].rgbRed == 0
2419 && bi->bmiColors[1].rgbGreen == 0
2420 && bi->bmiColors[1].rgbBlue == 0
2421 && bi->bmiColors[1].rgbReserved == 0)
2423 (bi->bmiColors[0].rgbRed == 0
2424 && bi->bmiColors[0].rgbGreen == 0
2425 && bi->bmiColors[0].rgbBlue == 0
2426 && bi->bmiColors[0].rgbReserved == 0
2427 && bi->bmiColors[1].rgbRed == 0xff
2428 && bi->bmiColors[1].rgbGreen == 0xff
2429 && bi->bmiColors[1].rgbBlue == 0xff
2430 && bi->bmiColors[1].rgbReserved == 0);
2433 else if (!monochrome)
2435 monochrome = ds.dsBm.bmBitsPixel == 1;
2438 if (monochrome)
2440 res = CreateBitmap(desiredx, desiredy, 1, 1, NULL);
2442 else
2444 HDC screenDC = GetDC(NULL);
2445 res = CreateCompatibleBitmap(screenDC, desiredx, desiredy);
2446 ReleaseDC(NULL, screenDC);
2450 if (res)
2452 /* Only copy the bitmap if it's a DIB section or if it's
2453 compatible to the screen */
2454 BOOL copyContents;
2456 if (objSize == sizeof(DIBSECTION))
2458 copyContents = TRUE;
2460 else
2462 HDC screenDC = GetDC(NULL);
2463 int screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
2464 ReleaseDC(NULL, screenDC);
2466 copyContents = (ds.dsBm.bmBitsPixel == 1 || ds.dsBm.bmBitsPixel == screen_depth);
2469 if (copyContents)
2471 /* The source bitmap may already be selected in a device context,
2472 use GetDIBits/StretchDIBits and not StretchBlt */
2474 HDC dc;
2475 void * bits;
2477 dc = CreateCompatibleDC(NULL);
2479 bi->bmiHeader.biWidth = ds.dsBm.bmWidth;
2480 bi->bmiHeader.biHeight = ds.dsBm.bmHeight;
2481 bi->bmiHeader.biSizeImage = 0;
2482 bi->bmiHeader.biClrUsed = 0;
2483 bi->bmiHeader.biClrImportant = 0;
2485 /* Fill in biSizeImage */
2486 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
2487 bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bi->bmiHeader.biSizeImage);
2489 if (bits)
2491 HBITMAP oldBmp;
2493 /* Get the image bits of the source bitmap */
2494 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS);
2496 /* Copy it to the destination bitmap */
2497 oldBmp = SelectObject(dc, res);
2498 StretchDIBits(dc, 0, 0, desiredx, desiredy,
2499 0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight,
2500 bits, bi, DIB_RGB_COLORS, SRCCOPY);
2501 SelectObject(dc, oldBmp);
2503 HeapFree(GetProcessHeap(), 0, bits);
2506 DeleteDC(dc);
2509 if (flags & LR_COPYDELETEORG)
2511 DeleteObject(hnd);
2514 HeapFree(GetProcessHeap(), 0, bi);
2515 return res;
2517 case IMAGE_ICON:
2518 return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags);
2519 case IMAGE_CURSOR:
2520 /* Should call CURSORICON_ExtCopy but more testing
2521 * needs to be done before we change this
2523 if (flags) FIXME("Flags are ignored\n");
2524 return CopyCursor(hnd);
2526 return 0;
2530 /******************************************************************************
2531 * LoadBitmapW (USER32.@) Loads bitmap from the executable file
2533 * RETURNS
2534 * Success: Handle to specified bitmap
2535 * Failure: NULL
2537 HBITMAP WINAPI LoadBitmapW(
2538 HINSTANCE instance, /* [in] Handle to application instance */
2539 LPCWSTR name) /* [in] Address of bitmap resource name */
2541 return LoadImageW( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2544 /**********************************************************************
2545 * LoadBitmapA (USER32.@)
2547 * See LoadBitmapW.
2549 HBITMAP WINAPI LoadBitmapA( HINSTANCE instance, LPCSTR name )
2551 return LoadImageA( instance, name, IMAGE_BITMAP, 0, 0, 0 );