2 * Cursor and icon support
4 * Copyright 1995 Alexandre Julliard
5 * 1996 Martin Von Loewis
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 * http://www.microsoft.com/win32dev/ui/icons.htm
29 * Cursors and icons are stored in a global heap block, with the
32 * CURSORICONINFO info;
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 ?!
51 #include "wine/winbase16.h"
52 #include "wine/winuser16.h"
53 #include "wine/exception.h"
55 #include "cursoricon.h"
57 #include "wine/debug.h"
63 #include "msvcrt/excpt.h"
65 WINE_DEFAULT_DEBUG_CHANNEL(cursor);
66 WINE_DECLARE_DEBUG_CHANNEL(icon);
67 WINE_DECLARE_DEBUG_CHANNEL(resource);
69 static RECT CURSOR_ClipRect; /* Cursor clipping rect */
73 /**********************************************************************
74 * ICONCACHE for cursors/icons loaded with LR_SHARED.
76 * FIXME: This should not be allocated on the system heap, but on a
77 * subsystem-global heap (i.e. one for all Win16 processes,
78 * and one for each Win32 process).
80 typedef struct tagICONCACHE
82 struct tagICONCACHE *next;
93 static ICONCACHE *IconAnchor = NULL;
94 static CRITICAL_SECTION IconCrst = CRITICAL_SECTION_INIT("IconCrst");
95 static WORD ICON_HOTSPOT = 0x4242;
98 /***********************************************************************
101 * Helper function to map a file to memory:
103 * [RETURN] ptr - pointer to mapped file
105 static void *map_fileW( LPCWSTR name )
107 HANDLE hFile, hMapping;
110 hFile = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL,
111 OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0 );
112 if (hFile != INVALID_HANDLE_VALUE)
114 hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
115 CloseHandle( hFile );
118 ptr = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
119 CloseHandle( hMapping );
126 /***********************************************************************
127 * get_bitmap_width_bytes
129 * Return number of bytes taken by a scanline of 16-bit aligned Windows DDB
132 static int get_bitmap_width_bytes( int width, int bpp )
137 return 2 * ((width+15) / 16);
139 return 2 * ((width+3) / 4);
144 return width + (width & 1);
151 WARN("Unknown depth %d, please report.\n", bpp );
157 /**********************************************************************
158 * CURSORICON_FindSharedIcon
160 static HANDLE CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
165 EnterCriticalSection( &IconCrst );
167 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
168 if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
171 handle = ptr->handle;
175 LeaveCriticalSection( &IconCrst );
180 /*************************************************************************
181 * CURSORICON_FindCache
183 * Given a handle, find the corresponding cache element
186 * Handle [I] handle to an Image
189 * Success: The cache entry
193 static ICONCACHE* CURSORICON_FindCache(HANDLE handle)
196 ICONCACHE *pRet=NULL;
197 BOOL IsFound = FALSE;
200 EnterCriticalSection( &IconCrst );
202 for (count = 0, ptr = IconAnchor; ptr != NULL && !IsFound; ptr = ptr->next, count++ )
204 if ( handle == ptr->handle )
211 LeaveCriticalSection( &IconCrst );
216 /**********************************************************************
217 * CURSORICON_AddSharedIcon
219 static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HRSRC hGroupRsrc, HANDLE handle )
221 ICONCACHE *ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(ICONCACHE) );
224 ptr->hModule = hModule;
226 ptr->handle = handle;
227 ptr->hGroupRsrc = hGroupRsrc;
230 EnterCriticalSection( &IconCrst );
231 ptr->next = IconAnchor;
233 LeaveCriticalSection( &IconCrst );
236 /**********************************************************************
237 * CURSORICON_DelSharedIcon
239 static INT CURSORICON_DelSharedIcon( HANDLE handle )
244 EnterCriticalSection( &IconCrst );
246 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
247 if ( ptr->handle == handle )
249 if ( ptr->count > 0 ) ptr->count--;
254 LeaveCriticalSection( &IconCrst );
259 /**********************************************************************
260 * CURSORICON_FreeModuleIcons
262 void CURSORICON_FreeModuleIcons( HMODULE hModule )
264 ICONCACHE **ptr = &IconAnchor;
266 if ( HIWORD( hModule ) )
267 hModule = MapHModuleLS( hModule );
269 hModule = GetExePtr( hModule );
271 EnterCriticalSection( &IconCrst );
275 if ( (*ptr)->hModule == hModule )
277 ICONCACHE *freePtr = *ptr;
278 *ptr = freePtr->next;
280 GlobalFree16( freePtr->handle );
281 HeapFree( GetProcessHeap(), 0, freePtr );
287 LeaveCriticalSection( &IconCrst );
290 /**********************************************************************
291 * CURSORICON_FindBestIcon
293 * Find the icon closest to the requested size and number of colors.
295 static CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
296 int height, int colors )
299 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
300 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
301 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
303 if (dir->idCount < 1)
305 WARN_(icon)("Empty directory!\n" );
308 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
311 iTotalDiff = 0xFFFFFFFF;
312 iColorDiff = 0xFFFFFFFF;
313 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
315 iTempXDiff = abs(width - entry->ResInfo.icon.bWidth);
316 iTempYDiff = abs(height - entry->ResInfo.icon.bHeight);
318 if(iTotalDiff > (iTempXDiff + iTempYDiff))
322 iTotalDiff = iXDiff + iYDiff;
326 /* Find Best Colors for Best Fit */
327 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
329 if(abs(width - entry->ResInfo.icon.bWidth) == iXDiff &&
330 abs(height - entry->ResInfo.icon.bHeight) == iYDiff)
332 iTempColorDiff = abs(colors - entry->ResInfo.icon.bColorCount);
333 if(iColorDiff > iTempColorDiff)
336 iColorDiff = iTempColorDiff;
345 /**********************************************************************
346 * CURSORICON_FindBestCursor
348 * Find the cursor closest to the requested size.
349 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
352 static CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
353 int width, int height, int color)
355 int i, maxwidth, maxheight;
356 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
358 if (dir->idCount < 1)
360 WARN_(cursor)("Empty directory!\n" );
363 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
365 /* Double height to account for AND and XOR masks */
369 /* First find the largest one smaller than or equal to the requested size*/
371 maxwidth = maxheight = 0;
372 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
373 if ((entry->ResInfo.cursor.wWidth <= width) && (entry->ResInfo.cursor.wHeight <= height) &&
374 (entry->ResInfo.cursor.wWidth > maxwidth) && (entry->ResInfo.cursor.wHeight > maxheight) &&
375 (entry->wBitCount == 1))
378 maxwidth = entry->ResInfo.cursor.wWidth;
379 maxheight = entry->ResInfo.cursor.wHeight;
381 if (bestEntry) return bestEntry;
383 /* Now find the smallest one larger than the requested size */
385 maxwidth = maxheight = 255;
386 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
387 if ((entry->ResInfo.cursor.wWidth < maxwidth) && (entry->ResInfo.cursor.wHeight < maxheight) &&
388 (entry->wBitCount == 1))
391 maxwidth = entry->ResInfo.cursor.wWidth;
392 maxheight = entry->ResInfo.cursor.wHeight;
398 /*********************************************************************
399 * The main purpose of this function is to create fake resource directory
400 * and fake resource entries. There are several reasons for this:
401 * - CURSORICONDIR and CURSORICONFILEDIR differ in sizes and their
403 * There are some "bad" cursor files which do not have
404 * bColorCount initialized but instead one must read this info
405 * directly from corresponding DIB sections
406 * Note: wResId is index to array of pointer returned in ptrs (origin is 1)
408 BOOL CURSORICON_SimulateLoadingFromResourceW( LPWSTR filename, BOOL fCursor,
409 CURSORICONDIR **res, LPBYTE **ptr)
412 CURSORICONFILEDIR *bits;
413 int entries, size, i;
417 if (!(bits = map_fileW( filename ))) return FALSE;
419 /* FIXME: test for inimated icons
420 * hack to load the first icon from the *.ani file
422 if ( *(LPDWORD)bits==0x46464952 ) /* "RIFF" */
423 { LPBYTE pos = (LPBYTE) bits;
424 FIXME_(cursor)("Animated icons not correctly implemented! %p \n", bits);
427 { if (*(LPDWORD)pos==0x6e6f6369) /* "icon" */
428 { FIXME_(cursor)("icon entry found! %p\n", bits);
430 if ( !*(LPWORD) pos==0x2fe) /* iconsize */
433 bits=(CURSORICONFILEDIR*)(pos+4);
434 FIXME_(cursor)("icon size ok. offset=%p \n", bits);
438 if (pos>=(LPBYTE)bits+766) goto fail;
441 if (!(entries = bits->idCount)) goto fail;
442 size = sizeof(CURSORICONDIR) + sizeof(CURSORICONDIRENTRY) * (entries - 1);
443 _free = (LPBYTE) size;
445 for (i=0; i < entries; i++)
446 size += bits->idEntries[i].dwDIBSize + (fCursor ? sizeof(POINT16): 0);
448 if (!(*ptr = HeapAlloc( GetProcessHeap(), 0,
449 entries * sizeof (CURSORICONDIRENTRY*)))) goto fail;
450 if (!(*res = HeapAlloc( GetProcessHeap(), 0, size))) goto fail;
452 _free = (LPBYTE)(*res) + (int)_free;
453 memcpy((*res), bits, 6);
454 for (i=0; i<entries; i++)
456 ((LPBYTE*)(*ptr))[i] = _free;
458 (*res)->idEntries[i].ResInfo.cursor.wWidth=bits->idEntries[i].bWidth;
459 (*res)->idEntries[i].ResInfo.cursor.wHeight=bits->idEntries[i].bHeight;
460 ((LPPOINT16)_free)->x=bits->idEntries[i].xHotspot;
461 ((LPPOINT16)_free)->y=bits->idEntries[i].yHotspot;
462 _free+=sizeof(POINT16);
464 (*res)->idEntries[i].ResInfo.icon.bWidth=bits->idEntries[i].bWidth;
465 (*res)->idEntries[i].ResInfo.icon.bHeight=bits->idEntries[i].bHeight;
466 (*res)->idEntries[i].ResInfo.icon.bColorCount = bits->idEntries[i].bColorCount;
468 (*res)->idEntries[i].wPlanes=1;
469 (*res)->idEntries[i].wBitCount = ((LPBITMAPINFOHEADER)((LPBYTE)bits +
470 bits->idEntries[i].dwDIBOffset))->biBitCount;
471 (*res)->idEntries[i].dwBytesInRes = bits->idEntries[i].dwDIBSize;
472 (*res)->idEntries[i].wResId=i+1;
474 memcpy(_free,(LPBYTE)bits +bits->idEntries[i].dwDIBOffset,
475 (*res)->idEntries[i].dwBytesInRes);
476 _free += (*res)->idEntries[i].dwBytesInRes;
478 UnmapViewOfFile( bits );
481 if (*res) HeapFree( GetProcessHeap(), 0, *res );
482 if (*ptr) HeapFree( GetProcessHeap(), 0, *ptr );
483 UnmapViewOfFile( bits );
488 /**********************************************************************
489 * CURSORICON_CreateFromResource
491 * Create a cursor or icon from in-memory resource template.
493 * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
494 * with cbSize parameter as well.
496 static HGLOBAL16 CURSORICON_CreateFromResource( HINSTANCE16 hInstance, HGLOBAL16 hObj, LPBYTE bits,
497 UINT cbSize, BOOL bIcon, DWORD dwVersion,
498 INT width, INT height, UINT loadflags )
501 int sizeAnd, sizeXor;
502 HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
503 BITMAP bmpXor, bmpAnd;
509 hotspot.x = ICON_HOTSPOT;
510 hotspot.y = ICON_HOTSPOT;
512 TRACE_(cursor)("%08x (%u bytes), ver %08x, %ix%i %s %s\n",
513 (unsigned)bits, cbSize, (unsigned)dwVersion, width, height,
514 bIcon ? "icon" : "cursor", (loadflags & LR_MONOCHROME) ? "mono" : "" );
515 if (dwVersion == 0x00020000)
517 FIXME_(cursor)("\t2.xx resources are not supported\n");
522 bmi = (BITMAPINFO *)bits;
523 else /* get the hotspot */
525 POINT16 *pt = (POINT16 *)bits;
527 bmi = (BITMAPINFO *)(pt + 1);
529 size = DIB_BitmapInfoSize( bmi, DIB_RGB_COLORS );
531 if (!width) width = bmi->bmiHeader.biWidth;
532 if (!height) height = bmi->bmiHeader.biHeight/2;
533 DoStretch = (bmi->bmiHeader.biHeight/2 != height) ||
534 (bmi->bmiHeader.biWidth != width);
536 /* Check bitmap header */
538 if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
539 (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) ||
540 bmi->bmiHeader.biCompression != BI_RGB) )
542 WARN_(cursor)("\tinvalid resource bitmap header.\n");
546 if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
551 /* Make sure we have room for the monochrome bitmap later on.
552 * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
553 * up to and including the biBitCount. In-memory icon resource
554 * format is as follows:
556 * BITMAPINFOHEADER icHeader // DIB header
557 * RGBQUAD icColors[] // Color table
558 * BYTE icXOR[] // DIB bits for XOR mask
559 * BYTE icAND[] // DIB bits for AND mask
562 if ((pInfo = (BITMAPINFO *)HeapAlloc( GetProcessHeap(), 0,
563 max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))))
565 memcpy( pInfo, bmi, size );
566 pInfo->bmiHeader.biHeight /= 2;
568 /* Create the XOR bitmap */
573 hXorBits = CreateCompatibleBitmap(screen_dc, width, height);
577 hXorBits = CreateBitmap(width, height, 1, 1, NULL);
584 if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
586 hOld = SelectObject(hdcMem, hXorBits);
587 res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
588 bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2,
589 (char*)bmi + size, pInfo, DIB_RGB_COLORS, SRCCOPY);
590 SelectObject(hdcMem, hOld);
592 if (!res) { DeleteObject(hXorBits); hXorBits = 0; }
594 } else hXorBits = CreateDIBitmap( screen_dc, &pInfo->bmiHeader,
595 CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS );
598 char* xbits = (char *)bmi + size +
599 DIB_GetDIBImageBytes(bmi->bmiHeader.biWidth,
600 bmi->bmiHeader.biHeight,
601 bmi->bmiHeader.biBitCount) / 2;
603 pInfo->bmiHeader.biBitCount = 1;
604 if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
606 RGBQUAD *rgb = pInfo->bmiColors;
608 pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
609 rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
610 rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
611 rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
615 RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
617 rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
618 rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
621 /* Create the AND bitmap */
624 if ((hAndBits = CreateBitmap(width, height, 1, 1, NULL))) {
628 if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
630 hOld = SelectObject(hdcMem, hAndBits);
631 res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
632 pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight,
633 xbits, pInfo, DIB_RGB_COLORS, SRCCOPY);
634 SelectObject(hdcMem, hOld);
636 if (!res) { DeleteObject(hAndBits); hAndBits = 0; }
638 } else hAndBits = CreateDIBitmap( screen_dc, &pInfo->bmiHeader,
639 CBM_INIT, xbits, pInfo, DIB_RGB_COLORS );
641 if( !hAndBits ) DeleteObject( hXorBits );
643 HeapFree( GetProcessHeap(), 0, pInfo );
647 if( !hXorBits || !hAndBits )
649 WARN_(cursor)("\tunable to create an icon bitmap.\n");
653 /* Now create the CURSORICONINFO structure */
654 GetObjectA( hXorBits, sizeof(bmpXor), &bmpXor );
655 GetObjectA( hAndBits, sizeof(bmpAnd), &bmpAnd );
656 sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
657 sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
659 if (hObj) hObj = GlobalReAlloc16( hObj,
660 sizeof(CURSORICONINFO) + sizeXor + sizeAnd, GMEM_MOVEABLE );
661 if (!hObj) hObj = GlobalAlloc16( GMEM_MOVEABLE,
662 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
665 CURSORICONINFO *info;
667 /* Make it owned by the module */
668 if (hInstance) hInstance = GetExePtr(hInstance);
669 FarSetOwner16( hObj, hInstance );
671 info = (CURSORICONINFO *)GlobalLock16( hObj );
672 info->ptHotSpot.x = hotspot.x;
673 info->ptHotSpot.y = hotspot.y;
674 info->nWidth = bmpXor.bmWidth;
675 info->nHeight = bmpXor.bmHeight;
676 info->nWidthBytes = bmpXor.bmWidthBytes;
677 info->bPlanes = bmpXor.bmPlanes;
678 info->bBitsPerPixel = bmpXor.bmBitsPixel;
680 /* Transfer the bitmap bits to the CURSORICONINFO structure */
682 GetBitmapBits( hAndBits, sizeAnd, (char *)(info + 1) );
683 GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
684 GlobalUnlock16( hObj );
687 DeleteObject( hAndBits );
688 DeleteObject( hXorBits );
693 /**********************************************************************
694 * CreateIconFromResource (USER32.@)
696 HICON WINAPI CreateIconFromResource( LPBYTE bits, UINT cbSize,
697 BOOL bIcon, DWORD dwVersion)
699 return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
703 /**********************************************************************
704 * CreateIconFromResourceEx (USER32.@)
706 HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
707 BOOL bIcon, DWORD dwVersion,
708 INT width, INT height,
711 return CURSORICON_CreateFromResource( 0, 0, bits, cbSize, bIcon, dwVersion,
712 width, height, cFlag );
715 /**********************************************************************
718 * Load a cursor or icon from resource or file.
720 HGLOBAL CURSORICON_Load( HINSTANCE hInstance, LPCWSTR name,
721 INT width, INT height, INT colors,
722 BOOL fCursor, UINT loadflags )
724 HANDLE handle = 0, h = 0;
727 CURSORICONDIRENTRY *dirEntry;
730 if ( loadflags & LR_LOADFROMFILE ) /* Load from file */
733 if (!CURSORICON_SimulateLoadingFromResourceW((LPWSTR)name, fCursor, &dir, &ptr))
736 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(dir, width, height, 1);
738 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(dir, width, height, colors);
739 bits = ptr[dirEntry->wResId-1];
740 h = CURSORICON_CreateFromResource( 0, 0, bits, dirEntry->dwBytesInRes,
741 !fCursor, 0x00030000, width, height, loadflags);
742 HeapFree( GetProcessHeap(), 0, dir );
743 HeapFree( GetProcessHeap(), 0, ptr );
745 else /* Load from resource */
751 if (!hInstance) /* Load OEM cursor/icon */
753 if (!(hInstance = GetModuleHandleA( "user32.dll" ))) return 0;
756 /* Normalize hInstance (must be uniquely represented for icon cache) */
758 if ( HIWORD( hInstance ) )
759 hInstance = MapHModuleLS( hInstance );
761 hInstance = GetExePtr( hInstance );
763 /* Get directory resource ID */
765 if (!(hRsrc = FindResourceW( hInstance, name,
766 fCursor ? RT_GROUP_CURSORW : RT_GROUP_ICONW )))
770 /* Find the best entry in the directory */
772 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
773 if (!(dir = (CURSORICONDIR*)LockResource( handle ))) return 0;
775 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor( dir,
778 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon( dir,
779 width, height, colors );
780 if (!dirEntry) return 0;
781 wResId = dirEntry->wResId;
782 dwBytesInRes = dirEntry->dwBytesInRes;
783 FreeResource( handle );
785 /* Load the resource */
787 if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
788 fCursor ? RT_CURSORW : RT_ICONW ))) return 0;
790 /* If shared icon, check whether it was already loaded */
791 if ( (loadflags & LR_SHARED)
792 && (h = CURSORICON_FindSharedIcon( hInstance, hRsrc ) ) != 0 )
795 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
796 bits = (LPBYTE)LockResource( handle );
797 h = CURSORICON_CreateFromResource( 0, 0, bits, dwBytesInRes,
798 !fCursor, 0x00030000, width, height, loadflags);
799 FreeResource( handle );
801 /* If shared icon, add to icon cache */
803 if ( h && (loadflags & LR_SHARED) )
804 CURSORICON_AddSharedIcon( hInstance, hRsrc, hGroupRsrc, h );
810 /***********************************************************************
813 * Make a copy of a cursor or icon.
815 static HGLOBAL16 CURSORICON_Copy( HINSTANCE16 hInstance, HGLOBAL16 handle )
817 char *ptrOld, *ptrNew;
821 if (!(ptrOld = (char *)GlobalLock16( handle ))) return 0;
822 if (hInstance && !(hInstance = GetExePtr( hInstance ))) return 0;
823 size = GlobalSize16( handle );
824 hNew = GlobalAlloc16( GMEM_MOVEABLE, size );
825 FarSetOwner16( hNew, hInstance );
826 ptrNew = (char *)GlobalLock16( hNew );
827 memcpy( ptrNew, ptrOld, size );
828 GlobalUnlock16( handle );
829 GlobalUnlock16( hNew );
833 /*************************************************************************
836 * Copies an Image from the Cache if LR_COPYFROMRESOURCE is specified
839 * Handle [I] handle to an Image
840 * nType [I] Type of Handle (IMAGE_CURSOR | IMAGE_ICON)
841 * iDesiredCX [I] The Desired width of the Image
842 * iDesiredCY [I] The desired height of the Image
843 * nFlags [I] The flags from CopyImage
846 * Success: The new handle of the Image
849 * LR_COPYDELETEORG and LR_MONOCHROME are currently not implemented.
850 * LR_MONOCHROME should be implemented by CURSORICON_CreateFromResource.
851 * LR_COPYFROMRESOURCE will only work if the Image is in the Cache.
856 HGLOBAL CURSORICON_ExtCopy(HGLOBAL Handle, UINT nType,
857 INT iDesiredCX, INT iDesiredCY,
862 TRACE_(icon)("Handle %u, uType %u, iDesiredCX %i, iDesiredCY %i, nFlags %u\n",
863 Handle, nType, iDesiredCX, iDesiredCY, nFlags);
870 /* Best Fit or Monochrome */
871 if( (nFlags & LR_COPYFROMRESOURCE
872 && (iDesiredCX > 0 || iDesiredCY > 0))
873 || nFlags & LR_MONOCHROME)
875 ICONCACHE* pIconCache = CURSORICON_FindCache(Handle);
877 /* Not Found in Cache, then do a straight copy
879 if(pIconCache == NULL)
881 hNew = CURSORICON_Copy(0, Handle);
882 if(nFlags & LR_COPYFROMRESOURCE)
884 TRACE_(icon)("LR_COPYFROMRESOURCE: Failed to load from cache\n");
889 int iTargetCY = iDesiredCY, iTargetCX = iDesiredCX;
896 CURSORICONDIRENTRY *pDirEntry;
897 BOOL bIsIcon = (nType == IMAGE_ICON);
899 /* Completing iDesiredCX CY for Monochrome Bitmaps if needed
901 if(((nFlags & LR_MONOCHROME) && !(nFlags & LR_COPYFROMRESOURCE))
902 || (iDesiredCX == 0 && iDesiredCY == 0))
904 iDesiredCY = GetSystemMetrics(bIsIcon ?
905 SM_CYICON : SM_CYCURSOR);
906 iDesiredCX = GetSystemMetrics(bIsIcon ?
907 SM_CXICON : SM_CXCURSOR);
910 /* Retrieve the CURSORICONDIRENTRY
912 if (!(hMem = LoadResource( pIconCache->hModule ,
913 pIconCache->hGroupRsrc)))
917 if (!(pDir = (CURSORICONDIR*)LockResource( hMem )))
926 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(
927 pDir, iDesiredCX, iDesiredCY, 256);
931 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(
932 pDir, iDesiredCX, iDesiredCY, 1);
935 wResId = pDirEntry->wResId;
936 dwBytesInRes = pDirEntry->dwBytesInRes;
939 TRACE_(icon)("ResID %u, BytesInRes %lu, Width %d, Height %d DX %d, DY %d\n",
940 wResId, dwBytesInRes, pDirEntry->ResInfo.icon.bWidth,
941 pDirEntry->ResInfo.icon.bHeight, iDesiredCX, iDesiredCY);
945 if (!(hRsrc = FindResourceW(pIconCache->hModule ,
946 MAKEINTRESOURCEW(wResId), bIsIcon ? RT_ICONW : RT_CURSORW)))
950 if (!(hMem = LoadResource( pIconCache->hModule , hRsrc )))
955 pBits = (LPBYTE)LockResource( hMem );
957 if(nFlags & LR_DEFAULTSIZE)
959 iTargetCY = GetSystemMetrics(SM_CYICON);
960 iTargetCX = GetSystemMetrics(SM_CXICON);
963 /* Create a New Icon with the proper dimension
965 hNew = CURSORICON_CreateFromResource( 0, 0, pBits, dwBytesInRes,
966 bIsIcon, 0x00030000, iTargetCX, iTargetCY, nFlags);
970 else hNew = CURSORICON_Copy(0, Handle);
975 /***********************************************************************
976 * CreateCursor (USER32.@)
978 HCURSOR WINAPI CreateCursor( HINSTANCE hInstance,
979 INT xHotSpot, INT yHotSpot,
980 INT nWidth, INT nHeight,
981 LPCVOID lpANDbits, LPCVOID lpXORbits )
985 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
986 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
988 info.ptHotSpot.x = xHotSpot;
989 info.ptHotSpot.y = yHotSpot;
990 info.nWidth = nWidth;
991 info.nHeight = nHeight;
992 info.nWidthBytes = 0;
994 info.bBitsPerPixel = 1;
996 return CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
1000 /***********************************************************************
1001 * CreateIcon (USER.407)
1003 HICON16 WINAPI CreateIcon16( HINSTANCE16 hInstance, INT16 nWidth,
1004 INT16 nHeight, BYTE bPlanes, BYTE bBitsPixel,
1005 LPCVOID lpANDbits, LPCVOID lpXORbits )
1007 CURSORICONINFO info;
1009 TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1010 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1012 info.ptHotSpot.x = ICON_HOTSPOT;
1013 info.ptHotSpot.y = ICON_HOTSPOT;
1014 info.nWidth = nWidth;
1015 info.nHeight = nHeight;
1016 info.nWidthBytes = 0;
1017 info.bPlanes = bPlanes;
1018 info.bBitsPerPixel = bBitsPixel;
1020 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1024 /***********************************************************************
1025 * CreateIcon (USER32.@)
1027 * Creates an icon based on the specified bitmaps. The bitmaps must be
1028 * provided in a device dependent format and will be resized to
1029 * (SM_CXICON,SM_CYICON) and depth converted to match the screen's color
1030 * depth. The provided bitmaps must be top-down bitmaps.
1031 * Although Windows does not support 15bpp(*) this API must support it
1032 * for Winelib applications.
1034 * (*) Windows does not support 15bpp but it supports the 555 RGB 16bpp
1039 * - The provided bitmaps are not resized!
1040 * - The documentation says the lpXORbits bitmap must be in a device
1041 * dependent format. But we must still resize it and perform depth
1042 * conversions if necessary.
1043 * - I'm a bit unsure about the how the 'device dependent format' thing works.
1044 * I did some tests on windows and found that if you provide a 16bpp bitmap
1045 * in lpXORbits, then its format but be 565 RGB if the screen's bit depth
1046 * is 16bpp but it must be 555 RGB if the screen's bit depth is anything
1047 * else. I don't know if this is part of the GDI specs or if this is a
1048 * quirk of the graphics card driver.
1049 * - You may think that we check whether the bit depths match or not
1050 * as an optimization. But the truth is that the conversion using
1051 * CreateDIBitmap does not work for some bit depth (e.g. 8bpp) and I have
1053 * - I'm pretty sure that all the things we do in CreateIcon should
1054 * also be done in CreateIconIndirect...
1056 HICON WINAPI CreateIcon(
1057 HINSTANCE hInstance, /* [in] the application's hInstance, currently unused */
1058 INT nWidth, /* [in] the width of the provided bitmaps */
1059 INT nHeight, /* [in] the height of the provided bitmaps */
1060 BYTE bPlanes, /* [in] the number of planes in the provided bitmaps */
1061 BYTE bBitsPixel, /* [in] the number of bits per pixel of the lpXORbits bitmap */
1062 LPCVOID lpANDbits, /* [in] a monochrome bitmap representing the icon's mask */
1063 LPCVOID lpXORbits) /* [in] the icon's 'color' bitmap */
1068 TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1069 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1075 if (GetDeviceCaps(hdc,BITSPIXEL)==bBitsPixel) {
1076 CURSORICONINFO info;
1078 info.ptHotSpot.x = ICON_HOTSPOT;
1079 info.ptHotSpot.y = ICON_HOTSPOT;
1080 info.nWidth = nWidth;
1081 info.nHeight = nHeight;
1082 info.nWidthBytes = 0;
1083 info.bPlanes = bPlanes;
1084 info.bBitsPerPixel = bBitsPixel;
1086 hIcon=CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
1092 iinfo.xHotspot=ICON_HOTSPOT;
1093 iinfo.yHotspot=ICON_HOTSPOT;
1094 iinfo.hbmMask=CreateBitmap(nWidth,nHeight,1,1,lpANDbits);
1096 bmi.bmiHeader.biSize=sizeof(bmi.bmiHeader);
1097 bmi.bmiHeader.biWidth=nWidth;
1098 bmi.bmiHeader.biHeight=-nHeight;
1099 bmi.bmiHeader.biPlanes=bPlanes;
1100 bmi.bmiHeader.biBitCount=bBitsPixel;
1101 bmi.bmiHeader.biCompression=BI_RGB;
1102 bmi.bmiHeader.biSizeImage=0;
1103 bmi.bmiHeader.biXPelsPerMeter=0;
1104 bmi.bmiHeader.biYPelsPerMeter=0;
1105 bmi.bmiHeader.biClrUsed=0;
1106 bmi.bmiHeader.biClrImportant=0;
1108 iinfo.hbmColor = CreateDIBitmap( hdc, &bmi.bmiHeader,
1109 CBM_INIT, lpXORbits,
1110 &bmi, DIB_RGB_COLORS );
1112 hIcon=CreateIconIndirect(&iinfo);
1113 DeleteObject(iinfo.hbmMask);
1114 DeleteObject(iinfo.hbmColor);
1121 /***********************************************************************
1122 * CreateCursorIconIndirect (USER.408)
1124 HGLOBAL16 WINAPI CreateCursorIconIndirect16( HINSTANCE16 hInstance,
1125 CURSORICONINFO *info,
1131 int sizeAnd, sizeXor;
1133 hInstance = GetExePtr( hInstance ); /* Make it a module handle */
1134 if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
1135 info->nWidthBytes = get_bitmap_width_bytes(info->nWidth,info->bBitsPerPixel);
1136 sizeXor = info->nHeight * info->nWidthBytes;
1137 sizeAnd = info->nHeight * get_bitmap_width_bytes( info->nWidth, 1 );
1138 if (!(handle = GlobalAlloc16( GMEM_MOVEABLE,
1139 sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
1141 FarSetOwner16( handle, hInstance );
1142 ptr = (char *)GlobalLock16( handle );
1143 memcpy( ptr, info, sizeof(*info) );
1144 memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
1145 memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
1146 GlobalUnlock16( handle );
1151 /***********************************************************************
1152 * CopyIcon (USER.368)
1154 HICON16 WINAPI CopyIcon16( HINSTANCE16 hInstance, HICON16 hIcon )
1156 TRACE_(icon)("%04x %04x\n", hInstance, hIcon );
1157 return CURSORICON_Copy( hInstance, hIcon );
1161 /***********************************************************************
1162 * CopyIcon (USER32.@)
1164 HICON WINAPI CopyIcon( HICON hIcon )
1166 TRACE_(icon)("%04x\n", hIcon );
1167 return CURSORICON_Copy( 0, hIcon );
1171 /***********************************************************************
1172 * CopyCursor (USER.369)
1174 HCURSOR16 WINAPI CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
1176 TRACE_(cursor)("%04x %04x\n", hInstance, hCursor );
1177 return CURSORICON_Copy( hInstance, hCursor );
1180 /**********************************************************************
1181 * DestroyIcon32 (USER.610)
1183 * This routine is actually exported from Win95 USER under the name
1184 * DestroyIcon32 ... The behaviour implemented here should mimic
1185 * the Win95 one exactly, especially the return values, which
1186 * depend on the setting of various flags.
1188 WORD WINAPI DestroyIcon32( HGLOBAL16 handle, UINT16 flags )
1192 TRACE_(icon)("(%04x, %04x)\n", handle, flags );
1194 /* Check whether destroying active cursor */
1196 if ( QUEUE_Current()->cursor == handle )
1198 WARN_(cursor)("Destroying active cursor!\n" );
1202 /* Try shared cursor/icon first */
1204 if ( !(flags & CID_NONSHARED) )
1206 INT count = CURSORICON_DelSharedIcon( handle );
1209 return (flags & CID_WIN32)? TRUE : (count == 0);
1211 /* FIXME: OEM cursors/icons should be recognized */
1214 /* Now assume non-shared cursor/icon */
1216 retv = GlobalFree16( handle );
1217 return (flags & CID_RESOURCE)? retv : TRUE;
1220 /***********************************************************************
1221 * DestroyIcon (USER32.@)
1223 BOOL WINAPI DestroyIcon( HICON hIcon )
1225 return DestroyIcon32( hIcon, CID_WIN32 );
1229 /***********************************************************************
1230 * DestroyCursor (USER32.@)
1232 BOOL WINAPI DestroyCursor( HCURSOR hCursor )
1234 return DestroyIcon32( hCursor, CID_WIN32 );
1238 /***********************************************************************
1239 * DrawIcon (USER32.@)
1241 BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
1243 CURSORICONINFO *ptr;
1245 HBITMAP hXorBits, hAndBits;
1246 COLORREF oldFg, oldBg;
1248 if (!(ptr = (CURSORICONINFO *)GlobalLock16( hIcon ))) return FALSE;
1249 if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
1250 hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1,
1252 hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
1253 ptr->bBitsPerPixel, (char *)(ptr + 1)
1254 + ptr->nHeight * get_bitmap_width_bytes(ptr->nWidth,1) );
1255 oldFg = SetTextColor( hdc, RGB(0,0,0) );
1256 oldBg = SetBkColor( hdc, RGB(255,255,255) );
1258 if (hXorBits && hAndBits)
1260 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1261 BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
1262 SelectObject( hMemDC, hXorBits );
1263 BitBlt(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
1264 SelectObject( hMemDC, hBitTemp );
1267 if (hXorBits) DeleteObject( hXorBits );
1268 if (hAndBits) DeleteObject( hAndBits );
1269 GlobalUnlock16( hIcon );
1270 SetTextColor( hdc, oldFg );
1271 SetBkColor( hdc, oldBg );
1275 /***********************************************************************
1276 * DumpIcon (USER.459)
1278 DWORD WINAPI DumpIcon16( SEGPTR pInfo, WORD *lpLen,
1279 SEGPTR *lpXorBits, SEGPTR *lpAndBits )
1281 CURSORICONINFO *info = MapSL( pInfo );
1282 int sizeAnd, sizeXor;
1284 if (!info) return 0;
1285 sizeXor = info->nHeight * info->nWidthBytes;
1286 sizeAnd = info->nHeight * get_bitmap_width_bytes( info->nWidth, 1 );
1287 if (lpAndBits) *lpAndBits = pInfo + sizeof(CURSORICONINFO);
1288 if (lpXorBits) *lpXorBits = pInfo + sizeof(CURSORICONINFO) + sizeAnd;
1289 if (lpLen) *lpLen = sizeof(CURSORICONINFO) + sizeAnd + sizeXor;
1290 return MAKELONG( sizeXor, sizeXor );
1294 /***********************************************************************
1295 * SetCursor (USER32.@)
1297 * A handle to the previous cursor shape.
1299 HCURSOR WINAPI SetCursor( HCURSOR hCursor /* [in] Handle of cursor to show */ )
1301 MESSAGEQUEUE *queue = QUEUE_Current();
1304 if (hCursor == queue->cursor) return hCursor; /* No change */
1305 TRACE_(cursor)("%04x\n", hCursor );
1306 hOldCursor = queue->cursor;
1307 queue->cursor = hCursor;
1308 /* Change the cursor shape only if it is visible */
1309 if (queue->cursor_count >= 0)
1311 USER_Driver.pSetCursor( (CURSORICONINFO*)GlobalLock16( hCursor ) );
1312 GlobalUnlock16( hCursor );
1317 /***********************************************************************
1318 * ShowCursor (USER32.@)
1320 INT WINAPI ShowCursor( BOOL bShow )
1322 MESSAGEQUEUE *queue = QUEUE_Current();
1324 TRACE_(cursor)("%d, count=%d\n", bShow, queue->cursor_count );
1328 if (++queue->cursor_count == 0) /* Show it */
1330 USER_Driver.pSetCursor( (CURSORICONINFO*)GlobalLock16( queue->cursor ) );
1331 GlobalUnlock16( queue->cursor );
1336 if (--queue->cursor_count == -1) /* Hide it */
1337 USER_Driver.pSetCursor( NULL );
1339 return queue->cursor_count;
1342 /***********************************************************************
1343 * GetCursor (USER32.@)
1345 HCURSOR WINAPI GetCursor(void)
1347 return QUEUE_Current()->cursor;
1351 /***********************************************************************
1352 * ClipCursor (USER.16)
1354 BOOL16 WINAPI ClipCursor16( const RECT16 *rect )
1356 if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1357 else CONV_RECT16TO32( rect, &CURSOR_ClipRect );
1362 /***********************************************************************
1363 * ClipCursor (USER32.@)
1365 BOOL WINAPI ClipCursor( const RECT *rect )
1367 if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1368 else CopyRect( &CURSOR_ClipRect, rect );
1373 /***********************************************************************
1374 * GetClipCursor (USER.309)
1376 void WINAPI GetClipCursor16( RECT16 *rect )
1378 if (rect) CONV_RECT32TO16( &CURSOR_ClipRect, rect );
1382 /***********************************************************************
1383 * GetClipCursor (USER32.@)
1385 BOOL WINAPI GetClipCursor( RECT *rect )
1389 CopyRect( rect, &CURSOR_ClipRect );
1395 /**********************************************************************
1396 * LookupIconIdFromDirectoryEx (USER.364)
1398 * FIXME: exact parameter sizes
1400 INT16 WINAPI LookupIconIdFromDirectoryEx16( LPBYTE xdir, BOOL16 bIcon,
1401 INT16 width, INT16 height, UINT16 cFlag )
1403 CURSORICONDIR *dir = (CURSORICONDIR*)xdir;
1405 if( dir && !dir->idReserved && (dir->idType & 3) )
1407 CURSORICONDIRENTRY* entry;
1412 palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
1415 colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
1420 entry = CURSORICON_FindBestIcon( dir, width, height, colors );
1422 entry = CURSORICON_FindBestCursor( dir, width, height, 1);
1424 if( entry ) retVal = entry->wResId;
1426 else WARN_(cursor)("invalid resource directory\n");
1430 /**********************************************************************
1431 * LookupIconIdFromDirectoryEx (USER32.@)
1433 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE dir, BOOL bIcon,
1434 INT width, INT height, UINT cFlag )
1436 return LookupIconIdFromDirectoryEx16( dir, bIcon, width, height, cFlag );
1439 /**********************************************************************
1440 * LookupIconIdFromDirectory (USER.?)
1442 INT16 WINAPI LookupIconIdFromDirectory16( LPBYTE dir, BOOL16 bIcon )
1444 return LookupIconIdFromDirectoryEx16( dir, bIcon,
1445 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1446 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1449 /**********************************************************************
1450 * LookupIconIdFromDirectory (USER32.@)
1452 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1454 return LookupIconIdFromDirectoryEx( dir, bIcon,
1455 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1456 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1459 /**********************************************************************
1460 * GetIconID (USER.455)
1462 WORD WINAPI GetIconID16( HGLOBAL16 hResource, DWORD resType )
1464 LPBYTE lpDir = (LPBYTE)GlobalLock16(hResource);
1466 TRACE_(cursor)("hRes=%04x, entries=%i\n",
1467 hResource, lpDir ? ((CURSORICONDIR*)lpDir)->idCount : 0);
1472 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, FALSE,
1473 GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1475 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, TRUE,
1476 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0 );
1478 WARN_(cursor)("invalid res type %ld\n", resType );
1483 /**********************************************************************
1484 * LoadCursorIconHandler (USER.336)
1486 * Supposed to load resources of Windows 2.x applications.
1488 HGLOBAL16 WINAPI LoadCursorIconHandler16( HGLOBAL16 hResource, HMODULE16 hModule, HRSRC16 hRsrc )
1490 FIXME_(cursor)("(%04x,%04x,%04x): old 2.x resources are not supported!\n",
1491 hResource, hModule, hRsrc);
1492 return (HGLOBAL16)0;
1495 /**********************************************************************
1496 * LoadDIBIconHandler (USER.357)
1498 * RT_ICON resource loader, installed by USER_SignalProc when module
1501 HGLOBAL16 WINAPI LoadDIBIconHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1503 /* If hResource is zero we must allocate a new memory block, if it's
1504 * non-zero but GlobalLock() returns NULL then it was discarded and
1505 * we have to recommit some memory, otherwise we just need to check
1506 * the block size. See LoadProc() in 16-bit SDK for more.
1509 hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1512 LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1513 hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1514 SizeofResource16(hModule, hRsrc), TRUE, 0x00030000,
1515 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR );
1520 /**********************************************************************
1521 * LoadDIBCursorHandler (USER.356)
1523 * RT_CURSOR resource loader. Same as above.
1525 HGLOBAL16 WINAPI LoadDIBCursorHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1527 hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1530 LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1531 hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1532 SizeofResource16(hModule, hRsrc), FALSE, 0x00030000,
1533 GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1538 /**********************************************************************
1539 * LoadIconHandler (USER.456)
1541 HICON16 WINAPI LoadIconHandler16( HGLOBAL16 hResource, BOOL16 bNew )
1543 LPBYTE bits = (LPBYTE)LockResource16( hResource );
1545 TRACE_(cursor)("hRes=%04x\n",hResource);
1547 return CURSORICON_CreateFromResource( 0, 0, bits, 0, TRUE,
1548 bNew ? 0x00030000 : 0x00020000, 0, 0, LR_DEFAULTCOLOR );
1551 /***********************************************************************
1552 * LoadCursorW (USER32.@)
1554 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
1556 return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0,
1557 LR_SHARED | LR_DEFAULTSIZE );
1560 /***********************************************************************
1561 * LoadCursorA (USER32.@)
1563 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
1565 return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0,
1566 LR_SHARED | LR_DEFAULTSIZE );
1569 /***********************************************************************
1570 * LoadCursorFromFileW (USER32.@)
1572 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
1574 return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0,
1575 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1578 /***********************************************************************
1579 * LoadCursorFromFileA (USER32.@)
1581 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
1583 return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0,
1584 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1587 /***********************************************************************
1588 * LoadIconW (USER32.@)
1590 HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
1592 return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0,
1593 LR_SHARED | LR_DEFAULTSIZE );
1596 /***********************************************************************
1597 * LoadIconA (USER32.@)
1599 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
1601 return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0,
1602 LR_SHARED | LR_DEFAULTSIZE );
1605 /**********************************************************************
1606 * GetIconInfo (USER32.@)
1608 BOOL WINAPI GetIconInfo(HICON hIcon,PICONINFO iconinfo) {
1609 CURSORICONINFO *ciconinfo;
1611 ciconinfo = GlobalLock16(hIcon);
1615 if ( (ciconinfo->ptHotSpot.x == ICON_HOTSPOT) &&
1616 (ciconinfo->ptHotSpot.y == ICON_HOTSPOT) )
1618 iconinfo->fIcon = TRUE;
1619 iconinfo->xHotspot = ciconinfo->nWidth / 2;
1620 iconinfo->yHotspot = ciconinfo->nHeight / 2;
1624 iconinfo->fIcon = FALSE;
1625 iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
1626 iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
1629 iconinfo->hbmColor = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1630 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
1631 (char *)(ciconinfo + 1)
1632 + ciconinfo->nHeight *
1633 get_bitmap_width_bytes (ciconinfo->nWidth,1) );
1634 iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1635 1, 1, (char *)(ciconinfo + 1));
1637 GlobalUnlock16(hIcon);
1642 /**********************************************************************
1643 * CreateIconIndirect (USER32.@)
1645 HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
1647 BITMAP bmpXor,bmpAnd;
1649 int sizeXor,sizeAnd;
1651 GetObjectA( iconinfo->hbmColor, sizeof(bmpXor), &bmpXor );
1652 GetObjectA( iconinfo->hbmMask, sizeof(bmpAnd), &bmpAnd );
1654 sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
1655 sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
1657 hObj = GlobalAlloc16( GMEM_MOVEABLE,
1658 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
1661 CURSORICONINFO *info;
1663 info = (CURSORICONINFO *)GlobalLock16( hObj );
1665 /* If we are creating an icon, the hotspot is unused */
1666 if (iconinfo->fIcon)
1668 info->ptHotSpot.x = ICON_HOTSPOT;
1669 info->ptHotSpot.y = ICON_HOTSPOT;
1673 info->ptHotSpot.x = iconinfo->xHotspot;
1674 info->ptHotSpot.y = iconinfo->yHotspot;
1677 info->nWidth = bmpXor.bmWidth;
1678 info->nHeight = bmpXor.bmHeight;
1679 info->nWidthBytes = bmpXor.bmWidthBytes;
1680 info->bPlanes = bmpXor.bmPlanes;
1681 info->bBitsPerPixel = bmpXor.bmBitsPixel;
1683 /* Transfer the bitmap bits to the CURSORICONINFO structure */
1685 GetBitmapBits( iconinfo->hbmMask ,sizeAnd,(char*)(info + 1) );
1686 GetBitmapBits( iconinfo->hbmColor,sizeXor,(char*)(info + 1) +sizeAnd);
1687 GlobalUnlock16( hObj );
1692 /******************************************************************************
1693 * DrawIconEx (USER32.@) Draws an icon or cursor on device context
1696 * Why is this using SM_CXICON instead of SM_CXCURSOR?
1699 * hdc [I] Handle to device context
1700 * x0 [I] X coordinate of upper left corner
1701 * y0 [I] Y coordinate of upper left corner
1702 * hIcon [I] Handle to icon to draw
1703 * cxWidth [I] Width of icon
1704 * cyWidth [I] Height of icon
1705 * istep [I] Index of frame in animated cursor
1706 * hbr [I] Handle to background brush
1707 * flags [I] Icon-drawing flags
1713 BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
1714 INT cxWidth, INT cyWidth, UINT istep,
1715 HBRUSH hbr, UINT flags )
1717 CURSORICONINFO *ptr = (CURSORICONINFO *)GlobalLock16 (hIcon);
1718 HDC hDC_off = 0, hMemDC = CreateCompatibleDC (hdc);
1719 BOOL result = FALSE, DoOffscreen;
1720 HBITMAP hB_off = 0, hOld = 0;
1722 if (!ptr) return FALSE;
1723 TRACE_(icon)("(hdc=%x,pos=%d.%d,hicon=%x,extend=%d.%d,istep=%d,br=%x,flags=0x%08x)\n",
1724 hdc,x0,y0,hIcon,cxWidth,cyWidth,istep,hbr,flags
1728 FIXME_(icon)("Ignoring istep=%d\n", istep);
1729 if (flags & DI_COMPAT)
1730 FIXME_(icon)("Ignoring flag DI_COMPAT\n");
1733 FIXME_(icon)("no flags set? setting to DI_NORMAL\n");
1737 /* Calculate the size of the destination image. */
1740 if (flags & DI_DEFAULTSIZE)
1741 cxWidth = GetSystemMetrics (SM_CXICON);
1743 cxWidth = ptr->nWidth;
1747 if (flags & DI_DEFAULTSIZE)
1748 cyWidth = GetSystemMetrics (SM_CYICON);
1750 cyWidth = ptr->nHeight;
1753 DoOffscreen = (GetObjectType( hbr ) == OBJ_BRUSH);
1763 hDC_off = CreateCompatibleDC(hdc);
1764 hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth);
1765 if (hDC_off && hB_off) {
1766 hOld = SelectObject(hDC_off, hB_off);
1767 FillRect(hDC_off, &r, hbr);
1771 if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
1773 HBITMAP hXorBits, hAndBits;
1774 COLORREF oldFg, oldBg;
1777 nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
1779 hXorBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1780 ptr->bPlanes, ptr->bBitsPerPixel,
1783 get_bitmap_width_bytes(ptr->nWidth,1) );
1784 hAndBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1785 1, 1, (char *)(ptr+1) );
1786 oldFg = SetTextColor( hdc, RGB(0,0,0) );
1787 oldBg = SetBkColor( hdc, RGB(255,255,255) );
1789 if (hXorBits && hAndBits)
1791 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1792 if (flags & DI_MASK)
1795 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1796 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1798 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
1799 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1801 SelectObject( hMemDC, hXorBits );
1802 if (flags & DI_IMAGE)
1805 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1806 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
1808 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
1809 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
1811 SelectObject( hMemDC, hBitTemp );
1815 SetTextColor( hdc, oldFg );
1816 SetBkColor( hdc, oldBg );
1817 if (hXorBits) DeleteObject( hXorBits );
1818 if (hAndBits) DeleteObject( hAndBits );
1819 SetStretchBltMode (hdc, nStretchMode);
1821 BitBlt(hdc, x0, y0, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
1822 SelectObject(hDC_off, hOld);
1825 if (hMemDC) DeleteDC( hMemDC );
1826 if (hDC_off) DeleteDC(hDC_off);
1827 if (hB_off) DeleteObject(hB_off);
1828 GlobalUnlock16( hIcon );
1832 /***********************************************************************
1833 * DIB_FixColorsToLoadflags
1835 * Change color table entries when LR_LOADTRANSPARENT or LR_LOADMAP3DCOLORS
1838 static void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags, BYTE pix)
1841 COLORREF c_W, c_S, c_F, c_L, c_C;
1845 if (bmi->bmiHeader.biBitCount > 8) return;
1846 if (bmi->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)) incr = 4;
1847 else if (bmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) incr = 3;
1849 WARN_(resource)("Wrong bitmap header size!\n");
1852 colors = bmi->bmiHeader.biClrUsed;
1853 if (!colors && (bmi->bmiHeader.biBitCount <= 8))
1854 colors = 1 << bmi->bmiHeader.biBitCount;
1855 c_W = GetSysColor(COLOR_WINDOW);
1856 c_S = GetSysColor(COLOR_3DSHADOW);
1857 c_F = GetSysColor(COLOR_3DFACE);
1858 c_L = GetSysColor(COLOR_3DLIGHT);
1859 if (loadflags & LR_LOADTRANSPARENT) {
1860 switch (bmi->bmiHeader.biBitCount) {
1861 case 1: pix = pix >> 7; break;
1862 case 4: pix = pix >> 4; break;
1865 WARN_(resource)("(%d): Unsupported depth\n", bmi->bmiHeader.biBitCount);
1868 if (pix >= colors) {
1869 WARN_(resource)("pixel has color index greater than biClrUsed!\n");
1872 if (loadflags & LR_LOADMAP3DCOLORS) c_W = c_F;
1873 ptr = (RGBQUAD*)((char*)bmi->bmiColors+pix*incr);
1874 ptr->rgbBlue = GetBValue(c_W);
1875 ptr->rgbGreen = GetGValue(c_W);
1876 ptr->rgbRed = GetRValue(c_W);
1878 if (loadflags & LR_LOADMAP3DCOLORS)
1879 for (i=0; i<colors; i++) {
1880 ptr = (RGBQUAD*)((char*)bmi->bmiColors+i*incr);
1881 c_C = RGB(ptr->rgbRed, ptr->rgbGreen, ptr->rgbBlue);
1882 if (c_C == RGB(128, 128, 128)) {
1883 ptr->rgbRed = GetRValue(c_S);
1884 ptr->rgbGreen = GetGValue(c_S);
1885 ptr->rgbBlue = GetBValue(c_S);
1886 } else if (c_C == RGB(192, 192, 192)) {
1887 ptr->rgbRed = GetRValue(c_F);
1888 ptr->rgbGreen = GetGValue(c_F);
1889 ptr->rgbBlue = GetBValue(c_F);
1890 } else if (c_C == RGB(223, 223, 223)) {
1891 ptr->rgbRed = GetRValue(c_L);
1892 ptr->rgbGreen = GetGValue(c_L);
1893 ptr->rgbBlue = GetBValue(c_L);
1899 /**********************************************************************
1902 static HBITMAP BITMAP_Load( HINSTANCE instance,LPCWSTR name, UINT loadflags )
1904 HBITMAP hbitmap = 0;
1908 BITMAPINFO *info, *fix_info=NULL;
1912 if (!(loadflags & LR_LOADFROMFILE))
1916 /* OEM bitmap: try to load the resource from user32.dll */
1917 if (HIWORD(name)) return 0;
1918 if (!(instance = GetModuleHandleA("user32.dll"))) return 0;
1920 if (!(hRsrc = FindResourceW( instance, name, RT_BITMAPW ))) return 0;
1921 if (!(handle = LoadResource( instance, hRsrc ))) return 0;
1923 if ((info = (BITMAPINFO *)LockResource( handle )) == NULL) return 0;
1927 if (!(ptr = map_fileW( name ))) return 0;
1928 info = (BITMAPINFO *)(ptr + sizeof(BITMAPFILEHEADER));
1930 size = DIB_BitmapInfoSize(info, DIB_RGB_COLORS);
1931 if ((hFix = GlobalAlloc(0, size))) fix_info=GlobalLock(hFix);
1935 memcpy(fix_info, info, size);
1936 pix = *((LPBYTE)info+DIB_BitmapInfoSize(info, DIB_RGB_COLORS));
1937 DIB_FixColorsToLoadflags(fix_info, loadflags, pix);
1938 if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
1941 char *bits = (char *)info + size;
1942 if (loadflags & LR_CREATEDIBSECTION) {
1944 hbitmap = CreateDIBSection(screen_dc, fix_info, DIB_RGB_COLORS, NULL, 0, 0);
1945 GetObjectA(hbitmap, sizeof(DIBSECTION), &dib);
1946 SetDIBits(screen_dc, hbitmap, 0, dib.dsBm.bmHeight, bits, info,
1950 hbitmap = CreateDIBitmap( screen_dc, &fix_info->bmiHeader, CBM_INIT,
1951 bits, fix_info, DIB_RGB_COLORS );
1957 if (loadflags & LR_LOADFROMFILE) UnmapViewOfFile( ptr );
1961 /**********************************************************************
1962 * LoadImageA (USER32.@)
1964 * FIXME: implementation lacks some features, see LR_ defines in winuser.h
1967 /* filter for page-fault exceptions */
1968 static WINE_EXCEPTION_FILTER(page_fault)
1970 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
1971 return EXCEPTION_EXECUTE_HANDLER;
1972 return EXCEPTION_CONTINUE_SEARCH;
1975 /*********************************************************************/
1977 HANDLE WINAPI LoadImageA( HINSTANCE hinst, LPCSTR name, UINT type,
1978 INT desiredx, INT desiredy, UINT loadflags)
1984 return LoadImageW(hinst, (LPWSTR)name, type, desiredx, desiredy, loadflags);
1987 DWORD len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
1988 u_name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1989 MultiByteToWideChar( CP_ACP, 0, name, -1, u_name, len );
1991 __EXCEPT(page_fault) {
1992 SetLastError( ERROR_INVALID_PARAMETER );
1996 res = LoadImageW(hinst, u_name, type, desiredx, desiredy, loadflags);
1997 HeapFree(GetProcessHeap(), 0, u_name);
2002 /******************************************************************************
2003 * LoadImageW (USER32.@) Loads an icon, cursor, or bitmap
2006 * hinst [I] Handle of instance that contains image
2007 * name [I] Name of image
2008 * type [I] Type of image
2009 * desiredx [I] Desired width
2010 * desiredy [I] Desired height
2011 * loadflags [I] Load flags
2014 * Success: Handle to newly loaded image
2017 * FIXME: Implementation lacks some features, see LR_ defines in winuser.h
2019 HANDLE WINAPI LoadImageW( HINSTANCE hinst, LPCWSTR name, UINT type,
2020 INT desiredx, INT desiredy, UINT loadflags )
2023 TRACE_(resource)("(0x%04x,%p,%d,%d,%d,0x%08x)\n",
2024 hinst,name,type,desiredx,desiredy,loadflags);
2026 TRACE_(resource)("(0x%04x,%p,%d,%d,%d,0x%08x)\n",
2027 hinst,name,type,desiredx,desiredy,loadflags);
2029 if (loadflags & LR_DEFAULTSIZE) {
2030 if (type == IMAGE_ICON) {
2031 if (!desiredx) desiredx = GetSystemMetrics(SM_CXICON);
2032 if (!desiredy) desiredy = GetSystemMetrics(SM_CYICON);
2033 } else if (type == IMAGE_CURSOR) {
2034 if (!desiredx) desiredx = GetSystemMetrics(SM_CXCURSOR);
2035 if (!desiredy) desiredy = GetSystemMetrics(SM_CYCURSOR);
2038 if (loadflags & LR_LOADFROMFILE) loadflags &= ~LR_SHARED;
2041 return BITMAP_Load( hinst, name, loadflags );
2044 if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
2047 UINT palEnts = GetSystemPaletteEntries(screen_dc, 0, 0, NULL);
2048 if (palEnts == 0) palEnts = 256;
2049 return CURSORICON_Load(hinst, name, desiredx, desiredy,
2050 palEnts, FALSE, loadflags);
2055 return CURSORICON_Load(hinst, name, desiredx, desiredy,
2056 1, TRUE, loadflags);
2061 /******************************************************************************
2062 * CopyImage (USER32.@) Creates new image and copies attributes to it
2065 * hnd [I] Handle to image to copy
2066 * type [I] Type of image to copy
2067 * desiredx [I] Desired width of new image
2068 * desiredy [I] Desired height of new image
2069 * flags [I] Copy flags
2072 * Success: Handle to newly created image
2075 * FIXME: implementation still lacks nearly all features, see LR_*
2076 * defines in winuser.h
2078 HICON WINAPI CopyImage( HANDLE hnd, UINT type, INT desiredx,
2079 INT desiredy, UINT flags )
2088 if (!GetObjectW( hnd, sizeof(bm), &bm )) return 0;
2090 if ((res = CreateBitmapIndirect(&bm)))
2092 char *buf = HeapAlloc( GetProcessHeap(), 0, bm.bmWidthBytes * bm.bmHeight );
2093 GetBitmapBits( hnd, bm.bmWidthBytes * bm.bmHeight, buf );
2094 SetBitmapBits( res, bm.bmWidthBytes * bm.bmHeight, buf );
2095 HeapFree( GetProcessHeap(), 0, buf );
2100 return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags);
2102 /* Should call CURSORICON_ExtCopy but more testing
2103 * needs to be done before we change this
2105 return CopyCursor(hnd);
2111 /******************************************************************************
2112 * LoadBitmapW (USER32.@) Loads bitmap from the executable file
2115 * Success: Handle to specified bitmap
2118 HBITMAP WINAPI LoadBitmapW(
2119 HINSTANCE instance, /* [in] Handle to application instance */
2120 LPCWSTR name) /* [in] Address of bitmap resource name */
2122 return LoadImageW( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2125 /**********************************************************************
2126 * LoadBitmapA (USER32.@)
2128 HBITMAP WINAPI LoadBitmapA( HINSTANCE instance, LPCSTR name )
2130 return LoadImageA( instance, name, IMAGE_BITMAP, 0, 0, 0 );