Convert HRSRC to a void*.
[wine/multimedia.git] / windows / cursoricon.c
blobe43af865575485c6046bb3b52e82a7c15bf05c70
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 * Theory:
27 * http://www.microsoft.com/win32dev/ui/icons.htm
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 <string.h>
47 #include <stdlib.h>
49 #include "windef.h"
50 #include "wingdi.h"
51 #include "wine/winbase16.h"
52 #include "wine/winuser16.h"
53 #include "wine/exception.h"
54 #include "bitmap.h"
55 #include "cursoricon.h"
56 #include "module.h"
57 #include "wine/debug.h"
58 #include "user.h"
59 #include "queue.h"
60 #include "input.h"
61 #include "message.h"
62 #include "winerror.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 */
71 static HDC screen_dc;
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;
84 HMODULE hModule;
85 HRSRC hRsrc;
86 HRSRC hGroupRsrc;
87 HANDLE handle;
89 INT count;
91 } ICONCACHE;
93 static ICONCACHE *IconAnchor = NULL;
94 static CRITICAL_SECTION IconCrst = CRITICAL_SECTION_INIT("IconCrst");
95 static WORD ICON_HOTSPOT = 0x4242;
98 /***********************************************************************
99 * map_fileW
101 * Helper function to map a file to memory:
102 * name - file name
103 * [RETURN] ptr - pointer to mapped file
105 static void *map_fileW( LPCWSTR name )
107 HANDLE hFile, hMapping;
108 LPVOID ptr = NULL;
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 );
116 if (hMapping)
118 ptr = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
119 CloseHandle( hMapping );
122 return ptr;
126 /***********************************************************************
127 * get_bitmap_width_bytes
129 * Return number of bytes taken by a scanline of 16-bit aligned Windows DDB
130 * data.
132 static int get_bitmap_width_bytes( int width, int bpp )
134 switch(bpp)
136 case 1:
137 return 2 * ((width+15) / 16);
138 case 4:
139 return 2 * ((width+3) / 4);
140 case 24:
141 width *= 3;
142 /* fall through */
143 case 8:
144 return width + (width & 1);
145 case 16:
146 case 15:
147 return width * 2;
148 case 32:
149 return width * 4;
150 default:
151 WARN("Unknown depth %d, please report.\n", bpp );
153 return -1;
157 /**********************************************************************
158 * CURSORICON_FindSharedIcon
160 static HANDLE CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
162 HANDLE handle = 0;
163 ICONCACHE *ptr;
165 EnterCriticalSection( &IconCrst );
167 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
168 if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
170 ptr->count++;
171 handle = ptr->handle;
172 break;
175 LeaveCriticalSection( &IconCrst );
177 return handle;
180 /*************************************************************************
181 * CURSORICON_FindCache
183 * Given a handle, find the corresponding cache element
185 * PARAMS
186 * Handle [I] handle to an Image
188 * RETURNS
189 * Success: The cache entry
190 * Failure: NULL
193 static ICONCACHE* CURSORICON_FindCache(HANDLE handle)
195 ICONCACHE *ptr;
196 ICONCACHE *pRet=NULL;
197 BOOL IsFound = FALSE;
198 int count;
200 EnterCriticalSection( &IconCrst );
202 for (count = 0, ptr = IconAnchor; ptr != NULL && !IsFound; ptr = ptr->next, count++ )
204 if ( handle == ptr->handle )
206 IsFound = TRUE;
207 pRet = ptr;
211 LeaveCriticalSection( &IconCrst );
213 return pRet;
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) );
222 if ( !ptr ) return;
224 ptr->hModule = hModule;
225 ptr->hRsrc = hRsrc;
226 ptr->handle = handle;
227 ptr->hGroupRsrc = hGroupRsrc;
228 ptr->count = 1;
230 EnterCriticalSection( &IconCrst );
231 ptr->next = IconAnchor;
232 IconAnchor = ptr;
233 LeaveCriticalSection( &IconCrst );
236 /**********************************************************************
237 * CURSORICON_DelSharedIcon
239 static INT CURSORICON_DelSharedIcon( HANDLE handle )
241 INT count = -1;
242 ICONCACHE *ptr;
244 EnterCriticalSection( &IconCrst );
246 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
247 if ( ptr->handle == handle )
249 if ( ptr->count > 0 ) ptr->count--;
250 count = ptr->count;
251 break;
254 LeaveCriticalSection( &IconCrst );
256 return count;
259 /**********************************************************************
260 * CURSORICON_FreeModuleIcons
262 void CURSORICON_FreeModuleIcons( HMODULE hModule )
264 ICONCACHE **ptr = &IconAnchor;
266 if ( HIWORD( hModule ) )
267 hModule = MapHModuleLS( hModule );
268 else
269 hModule = GetExePtr( hModule );
271 EnterCriticalSection( &IconCrst );
273 while ( *ptr )
275 if ( (*ptr)->hModule == hModule )
277 ICONCACHE *freePtr = *ptr;
278 *ptr = freePtr->next;
280 GlobalFree16( freePtr->handle );
281 HeapFree( GetProcessHeap(), 0, freePtr );
282 continue;
284 ptr = &(*ptr)->next;
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 )
298 int i;
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" );
306 return NULL;
308 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
310 /* Find Best Fit */
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))
320 iXDiff = iTempXDiff;
321 iYDiff = 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)
335 bestEntry = entry;
336 iColorDiff = iTempColorDiff;
341 return bestEntry;
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
350 * ignored too
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" );
361 return NULL;
363 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
365 /* Double height to account for AND and XOR masks */
367 height *= 2;
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))
377 bestEntry = entry;
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))
390 bestEntry = entry;
391 maxwidth = entry->ResInfo.cursor.wWidth;
392 maxheight = entry->ResInfo.cursor.wHeight;
395 return bestEntry;
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
402 * fields
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)
411 LPBYTE _free;
412 CURSORICONFILEDIR *bits;
413 int entries, size, i;
415 *res = NULL;
416 *ptr = NULL;
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);
426 for (;;)
427 { if (*(LPDWORD)pos==0x6e6f6369) /* "icon" */
428 { FIXME_(cursor)("icon entry found! %p\n", bits);
429 pos+=4;
430 if ( !*(LPWORD) pos==0x2fe) /* iconsize */
431 { goto fail;
433 bits=(CURSORICONFILEDIR*)(pos+4);
434 FIXME_(cursor)("icon size ok. offset=%p \n", bits);
435 break;
437 pos+=2;
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;
457 if (fCursor) {
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);
463 } else {
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 );
479 return TRUE;
480 fail:
481 if (*res) HeapFree( GetProcessHeap(), 0, *res );
482 if (*ptr) HeapFree( GetProcessHeap(), 0, *ptr );
483 UnmapViewOfFile( bits );
484 return FALSE;
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 )
500 static HDC hdcMem;
501 int sizeAnd, sizeXor;
502 HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
503 BITMAP bmpXor, bmpAnd;
504 POINT16 hotspot;
505 BITMAPINFO *bmi;
506 BOOL DoStretch;
507 INT size;
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");
518 return 0;
521 if (bIcon)
522 bmi = (BITMAPINFO *)bits;
523 else /* get the hotspot */
525 POINT16 *pt = (POINT16 *)bits;
526 hotspot = *pt;
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");
543 return 0;
546 if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
547 if (screen_dc)
549 BITMAPINFO* pInfo;
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 */
570 if (DoStretch) {
571 if(bIcon)
573 hXorBits = CreateCompatibleBitmap(screen_dc, width, height);
575 else
577 hXorBits = CreateBitmap(width, height, 1, 1, NULL);
579 if(hXorBits)
581 HBITMAP hOld;
582 BOOL res = FALSE;
584 if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
585 if (hdcMem) {
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 );
596 if( hXorBits )
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;
613 else
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 */
623 if (DoStretch) {
624 if ((hAndBits = CreateBitmap(width, height, 1, 1, NULL))) {
625 HBITMAP hOld;
626 BOOL res = FALSE;
628 if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
629 if (hdcMem) {
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");
650 return 0;
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 );
663 if (hObj)
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 );
689 return hObj;
693 /**********************************************************************
694 * CreateIconFromResourceEx (USER.450)
696 * FIXME: not sure about exact parameter types
698 HICON16 WINAPI CreateIconFromResourceEx16( LPBYTE bits, UINT16 cbSize, BOOL16 bIcon,
699 DWORD dwVersion, INT16 width, INT16 height, UINT16 cFlag )
701 return CreateIconFromResourceEx(bits, cbSize, bIcon, dwVersion,
702 width, height, cFlag);
706 /**********************************************************************
707 * CreateIconFromResource (USER32.@)
709 HICON WINAPI CreateIconFromResource( LPBYTE bits, UINT cbSize,
710 BOOL bIcon, DWORD dwVersion)
712 return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
716 /**********************************************************************
717 * CreateIconFromResourceEx (USER32.@)
719 HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
720 BOOL bIcon, DWORD dwVersion,
721 INT width, INT height,
722 UINT cFlag )
724 return CURSORICON_CreateFromResource( 0, 0, bits, cbSize, bIcon, dwVersion,
725 width, height, cFlag );
728 /**********************************************************************
729 * CURSORICON_Load
731 * Load a cursor or icon from resource or file.
733 HGLOBAL CURSORICON_Load( HINSTANCE hInstance, LPCWSTR name,
734 INT width, INT height, INT colors,
735 BOOL fCursor, UINT loadflags )
737 HANDLE handle = 0, h = 0;
738 HRSRC hRsrc;
739 CURSORICONDIR *dir;
740 CURSORICONDIRENTRY *dirEntry;
741 LPBYTE bits;
743 if ( loadflags & LR_LOADFROMFILE ) /* Load from file */
745 LPBYTE *ptr;
746 if (!CURSORICON_SimulateLoadingFromResourceW((LPWSTR)name, fCursor, &dir, &ptr))
747 return 0;
748 if (fCursor)
749 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(dir, width, height, 1);
750 else
751 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(dir, width, height, colors);
752 bits = ptr[dirEntry->wResId-1];
753 h = CURSORICON_CreateFromResource( 0, 0, bits, dirEntry->dwBytesInRes,
754 !fCursor, 0x00030000, width, height, loadflags);
755 HeapFree( GetProcessHeap(), 0, dir );
756 HeapFree( GetProcessHeap(), 0, ptr );
758 else /* Load from resource */
760 HRSRC hGroupRsrc;
761 WORD wResId;
762 DWORD dwBytesInRes;
764 if (!hInstance) /* Load OEM cursor/icon */
766 if (!(hInstance = GetModuleHandleA( "user32.dll" ))) return 0;
769 /* Normalize hInstance (must be uniquely represented for icon cache) */
771 if ( HIWORD( hInstance ) )
772 hInstance = MapHModuleLS( hInstance );
773 else
774 hInstance = GetExePtr( hInstance );
776 /* Get directory resource ID */
778 if (!(hRsrc = FindResourceW( hInstance, name,
779 fCursor ? RT_GROUP_CURSORW : RT_GROUP_ICONW )))
780 return 0;
781 hGroupRsrc = hRsrc;
783 /* Find the best entry in the directory */
785 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
786 if (!(dir = (CURSORICONDIR*)LockResource( handle ))) return 0;
787 if (fCursor)
788 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor( dir,
789 width, height, 1);
790 else
791 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon( dir,
792 width, height, colors );
793 if (!dirEntry) return 0;
794 wResId = dirEntry->wResId;
795 dwBytesInRes = dirEntry->dwBytesInRes;
796 FreeResource( handle );
798 /* Load the resource */
800 if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
801 fCursor ? RT_CURSORW : RT_ICONW ))) return 0;
803 /* If shared icon, check whether it was already loaded */
804 if ( (loadflags & LR_SHARED)
805 && (h = CURSORICON_FindSharedIcon( hInstance, hRsrc ) ) != 0 )
806 return h;
808 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
809 bits = (LPBYTE)LockResource( handle );
810 h = CURSORICON_CreateFromResource( 0, 0, bits, dwBytesInRes,
811 !fCursor, 0x00030000, width, height, loadflags);
812 FreeResource( handle );
814 /* If shared icon, add to icon cache */
816 if ( h && (loadflags & LR_SHARED) )
817 CURSORICON_AddSharedIcon( hInstance, hRsrc, hGroupRsrc, h );
820 return h;
823 /***********************************************************************
824 * CURSORICON_Copy
826 * Make a copy of a cursor or icon.
828 static HGLOBAL16 CURSORICON_Copy( HINSTANCE16 hInstance, HGLOBAL16 handle )
830 char *ptrOld, *ptrNew;
831 int size;
832 HGLOBAL16 hNew;
834 if (!(ptrOld = (char *)GlobalLock16( handle ))) return 0;
835 if (hInstance && !(hInstance = GetExePtr( hInstance ))) return 0;
836 size = GlobalSize16( handle );
837 hNew = GlobalAlloc16( GMEM_MOVEABLE, size );
838 FarSetOwner16( hNew, hInstance );
839 ptrNew = (char *)GlobalLock16( hNew );
840 memcpy( ptrNew, ptrOld, size );
841 GlobalUnlock16( handle );
842 GlobalUnlock16( hNew );
843 return hNew;
846 /*************************************************************************
847 * CURSORICON_ExtCopy
849 * Copies an Image from the Cache if LR_COPYFROMRESOURCE is specified
851 * PARAMS
852 * Handle [I] handle to an Image
853 * nType [I] Type of Handle (IMAGE_CURSOR | IMAGE_ICON)
854 * iDesiredCX [I] The Desired width of the Image
855 * iDesiredCY [I] The desired height of the Image
856 * nFlags [I] The flags from CopyImage
858 * RETURNS
859 * Success: The new handle of the Image
861 * NOTES
862 * LR_COPYDELETEORG and LR_MONOCHROME are currently not implemented.
863 * LR_MONOCHROME should be implemented by CURSORICON_CreateFromResource.
864 * LR_COPYFROMRESOURCE will only work if the Image is in the Cache.
869 HGLOBAL CURSORICON_ExtCopy(HGLOBAL Handle, UINT nType,
870 INT iDesiredCX, INT iDesiredCY,
871 UINT nFlags)
873 HGLOBAL16 hNew=0;
875 TRACE_(icon)("Handle %u, uType %u, iDesiredCX %i, iDesiredCY %i, nFlags %u\n",
876 Handle, nType, iDesiredCX, iDesiredCY, nFlags);
878 if(Handle == 0)
880 return 0;
883 /* Best Fit or Monochrome */
884 if( (nFlags & LR_COPYFROMRESOURCE
885 && (iDesiredCX > 0 || iDesiredCY > 0))
886 || nFlags & LR_MONOCHROME)
888 ICONCACHE* pIconCache = CURSORICON_FindCache(Handle);
890 /* Not Found in Cache, then do a straight copy
892 if(pIconCache == NULL)
894 hNew = CURSORICON_Copy(0, Handle);
895 if(nFlags & LR_COPYFROMRESOURCE)
897 TRACE_(icon)("LR_COPYFROMRESOURCE: Failed to load from cache\n");
900 else
902 int iTargetCY = iDesiredCY, iTargetCX = iDesiredCX;
903 LPBYTE pBits;
904 HANDLE hMem;
905 HRSRC hRsrc;
906 DWORD dwBytesInRes;
907 WORD wResId;
908 CURSORICONDIR *pDir;
909 CURSORICONDIRENTRY *pDirEntry;
910 BOOL bIsIcon = (nType == IMAGE_ICON);
912 /* Completing iDesiredCX CY for Monochrome Bitmaps if needed
914 if(((nFlags & LR_MONOCHROME) && !(nFlags & LR_COPYFROMRESOURCE))
915 || (iDesiredCX == 0 && iDesiredCY == 0))
917 iDesiredCY = GetSystemMetrics(bIsIcon ?
918 SM_CYICON : SM_CYCURSOR);
919 iDesiredCX = GetSystemMetrics(bIsIcon ?
920 SM_CXICON : SM_CXCURSOR);
923 /* Retrieve the CURSORICONDIRENTRY
925 if (!(hMem = LoadResource( pIconCache->hModule ,
926 pIconCache->hGroupRsrc)))
928 return 0;
930 if (!(pDir = (CURSORICONDIR*)LockResource( hMem )))
932 return 0;
935 /* Find Best Fit
937 if(bIsIcon)
939 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(
940 pDir, iDesiredCX, iDesiredCY, 256);
942 else
944 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(
945 pDir, iDesiredCX, iDesiredCY, 1);
948 wResId = pDirEntry->wResId;
949 dwBytesInRes = pDirEntry->dwBytesInRes;
950 FreeResource(hMem);
952 TRACE_(icon)("ResID %u, BytesInRes %lu, Width %d, Height %d DX %d, DY %d\n",
953 wResId, dwBytesInRes, pDirEntry->ResInfo.icon.bWidth,
954 pDirEntry->ResInfo.icon.bHeight, iDesiredCX, iDesiredCY);
956 /* Get the Best Fit
958 if (!(hRsrc = FindResourceW(pIconCache->hModule ,
959 MAKEINTRESOURCEW(wResId), bIsIcon ? RT_ICONW : RT_CURSORW)))
961 return 0;
963 if (!(hMem = LoadResource( pIconCache->hModule , hRsrc )))
965 return 0;
968 pBits = (LPBYTE)LockResource( hMem );
970 if(nFlags & LR_DEFAULTSIZE)
972 iTargetCY = GetSystemMetrics(SM_CYICON);
973 iTargetCX = GetSystemMetrics(SM_CXICON);
976 /* Create a New Icon with the proper dimension
978 hNew = CURSORICON_CreateFromResource( 0, 0, pBits, dwBytesInRes,
979 bIsIcon, 0x00030000, iTargetCX, iTargetCY, nFlags);
980 FreeResource(hMem);
983 else hNew = CURSORICON_Copy(0, Handle);
984 return hNew;
988 /***********************************************************************
989 * LoadCursor (USER.173)
991 HCURSOR16 WINAPI LoadCursor16( HINSTANCE16 hInstance, LPCSTR name )
993 return LoadCursorA( hInstance, name );
997 /***********************************************************************
998 * LoadIcon (USER.174)
1000 HICON16 WINAPI LoadIcon16( HINSTANCE16 hInstance, LPCSTR name )
1002 return LoadIconA( hInstance, name );
1006 /***********************************************************************
1007 * CreateCursor (USER.406)
1009 HCURSOR16 WINAPI CreateCursor16( HINSTANCE16 hInstance,
1010 INT16 xHotSpot, INT16 yHotSpot,
1011 INT16 nWidth, INT16 nHeight,
1012 LPCVOID lpANDbits, LPCVOID lpXORbits )
1014 CURSORICONINFO info;
1016 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1017 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1019 info.ptHotSpot.x = xHotSpot;
1020 info.ptHotSpot.y = yHotSpot;
1021 info.nWidth = nWidth;
1022 info.nHeight = nHeight;
1023 info.nWidthBytes = 0;
1024 info.bPlanes = 1;
1025 info.bBitsPerPixel = 1;
1027 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1031 /***********************************************************************
1032 * CreateCursor (USER32.@)
1034 HCURSOR WINAPI CreateCursor( HINSTANCE hInstance,
1035 INT xHotSpot, INT yHotSpot,
1036 INT nWidth, INT nHeight,
1037 LPCVOID lpANDbits, LPCVOID lpXORbits )
1039 CURSORICONINFO info;
1041 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1042 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1044 info.ptHotSpot.x = xHotSpot;
1045 info.ptHotSpot.y = yHotSpot;
1046 info.nWidth = nWidth;
1047 info.nHeight = nHeight;
1048 info.nWidthBytes = 0;
1049 info.bPlanes = 1;
1050 info.bBitsPerPixel = 1;
1052 return CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
1056 /***********************************************************************
1057 * CreateIcon (USER.407)
1059 HICON16 WINAPI CreateIcon16( HINSTANCE16 hInstance, INT16 nWidth,
1060 INT16 nHeight, BYTE bPlanes, BYTE bBitsPixel,
1061 LPCVOID lpANDbits, LPCVOID lpXORbits )
1063 CURSORICONINFO info;
1065 TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1066 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1068 info.ptHotSpot.x = ICON_HOTSPOT;
1069 info.ptHotSpot.y = ICON_HOTSPOT;
1070 info.nWidth = nWidth;
1071 info.nHeight = nHeight;
1072 info.nWidthBytes = 0;
1073 info.bPlanes = bPlanes;
1074 info.bBitsPerPixel = bBitsPixel;
1076 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1080 /***********************************************************************
1081 * CreateIcon (USER32.@)
1083 * Creates an icon based on the specified bitmaps. The bitmaps must be
1084 * provided in a device dependent format and will be resized to
1085 * (SM_CXICON,SM_CYICON) and depth converted to match the screen's color
1086 * depth. The provided bitmaps must be top-down bitmaps.
1087 * Although Windows does not support 15bpp(*) this API must support it
1088 * for Winelib applications.
1090 * (*) Windows does not support 15bpp but it supports the 555 RGB 16bpp
1091 * format!
1093 * BUGS
1095 * - The provided bitmaps are not resized!
1096 * - The documentation says the lpXORbits bitmap must be in a device
1097 * dependent format. But we must still resize it and perform depth
1098 * conversions if necessary.
1099 * - I'm a bit unsure about the how the 'device dependent format' thing works.
1100 * I did some tests on windows and found that if you provide a 16bpp bitmap
1101 * in lpXORbits, then its format but be 565 RGB if the screen's bit depth
1102 * is 16bpp but it must be 555 RGB if the screen's bit depth is anything
1103 * else. I don't know if this is part of the GDI specs or if this is a
1104 * quirk of the graphics card driver.
1105 * - You may think that we check whether the bit depths match or not
1106 * as an optimization. But the truth is that the conversion using
1107 * CreateDIBitmap does not work for some bit depth (e.g. 8bpp) and I have
1108 * no idea why.
1109 * - I'm pretty sure that all the things we do in CreateIcon should
1110 * also be done in CreateIconIndirect...
1112 HICON WINAPI CreateIcon(
1113 HINSTANCE hInstance, /* [in] the application's hInstance, currently unused */
1114 INT nWidth, /* [in] the width of the provided bitmaps */
1115 INT nHeight, /* [in] the height of the provided bitmaps */
1116 BYTE bPlanes, /* [in] the number of planes in the provided bitmaps */
1117 BYTE bBitsPixel, /* [in] the number of bits per pixel of the lpXORbits bitmap */
1118 LPCVOID lpANDbits, /* [in] a monochrome bitmap representing the icon's mask */
1119 LPCVOID lpXORbits) /* [in] the icon's 'color' bitmap */
1121 HICON hIcon;
1122 HDC hdc;
1124 TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1125 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1127 hdc=GetDC(0);
1128 if (!hdc)
1129 return 0;
1131 if (GetDeviceCaps(hdc,BITSPIXEL)==bBitsPixel) {
1132 CURSORICONINFO info;
1134 info.ptHotSpot.x = ICON_HOTSPOT;
1135 info.ptHotSpot.y = ICON_HOTSPOT;
1136 info.nWidth = nWidth;
1137 info.nHeight = nHeight;
1138 info.nWidthBytes = 0;
1139 info.bPlanes = bPlanes;
1140 info.bBitsPerPixel = bBitsPixel;
1142 hIcon=CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
1143 } else {
1144 ICONINFO iinfo;
1145 BITMAPINFO bmi;
1147 iinfo.fIcon=TRUE;
1148 iinfo.xHotspot=ICON_HOTSPOT;
1149 iinfo.yHotspot=ICON_HOTSPOT;
1150 iinfo.hbmMask=CreateBitmap(nWidth,nHeight,1,1,lpANDbits);
1152 bmi.bmiHeader.biSize=sizeof(bmi.bmiHeader);
1153 bmi.bmiHeader.biWidth=nWidth;
1154 bmi.bmiHeader.biHeight=-nHeight;
1155 bmi.bmiHeader.biPlanes=bPlanes;
1156 bmi.bmiHeader.biBitCount=bBitsPixel;
1157 bmi.bmiHeader.biCompression=BI_RGB;
1158 bmi.bmiHeader.biSizeImage=0;
1159 bmi.bmiHeader.biXPelsPerMeter=0;
1160 bmi.bmiHeader.biYPelsPerMeter=0;
1161 bmi.bmiHeader.biClrUsed=0;
1162 bmi.bmiHeader.biClrImportant=0;
1164 iinfo.hbmColor = CreateDIBitmap( hdc, &bmi.bmiHeader,
1165 CBM_INIT, lpXORbits,
1166 &bmi, DIB_RGB_COLORS );
1168 hIcon=CreateIconIndirect(&iinfo);
1169 DeleteObject(iinfo.hbmMask);
1170 DeleteObject(iinfo.hbmColor);
1172 ReleaseDC(0,hdc);
1173 return hIcon;
1177 /***********************************************************************
1178 * CreateCursorIconIndirect (USER.408)
1180 HGLOBAL16 WINAPI CreateCursorIconIndirect16( HINSTANCE16 hInstance,
1181 CURSORICONINFO *info,
1182 LPCVOID lpANDbits,
1183 LPCVOID lpXORbits )
1185 HGLOBAL16 handle;
1186 char *ptr;
1187 int sizeAnd, sizeXor;
1189 hInstance = GetExePtr( hInstance ); /* Make it a module handle */
1190 if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
1191 info->nWidthBytes = get_bitmap_width_bytes(info->nWidth,info->bBitsPerPixel);
1192 sizeXor = info->nHeight * info->nWidthBytes;
1193 sizeAnd = info->nHeight * get_bitmap_width_bytes( info->nWidth, 1 );
1194 if (!(handle = GlobalAlloc16( GMEM_MOVEABLE,
1195 sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
1196 return 0;
1197 FarSetOwner16( handle, hInstance );
1198 ptr = (char *)GlobalLock16( handle );
1199 memcpy( ptr, info, sizeof(*info) );
1200 memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
1201 memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
1202 GlobalUnlock16( handle );
1203 return handle;
1207 /***********************************************************************
1208 * CopyIcon (USER.368)
1210 HICON16 WINAPI CopyIcon16( HINSTANCE16 hInstance, HICON16 hIcon )
1212 TRACE_(icon)("%04x %04x\n", hInstance, hIcon );
1213 return CURSORICON_Copy( hInstance, hIcon );
1217 /***********************************************************************
1218 * CopyIcon (USER32.@)
1220 HICON WINAPI CopyIcon( HICON hIcon )
1222 TRACE_(icon)("%04x\n", hIcon );
1223 return CURSORICON_Copy( 0, hIcon );
1227 /***********************************************************************
1228 * CopyCursor (USER.369)
1230 HCURSOR16 WINAPI CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
1232 TRACE_(cursor)("%04x %04x\n", hInstance, hCursor );
1233 return CURSORICON_Copy( hInstance, hCursor );
1236 /**********************************************************************
1237 * DestroyIcon32 (USER.610)
1238 * DestroyIcon32 (USER32.@)
1240 * This routine is actually exported from Win95 USER under the name
1241 * DestroyIcon32 ... The behaviour implemented here should mimic
1242 * the Win95 one exactly, especially the return values, which
1243 * depend on the setting of various flags.
1245 WORD WINAPI DestroyIcon32( HGLOBAL16 handle, UINT16 flags )
1247 WORD retv;
1249 TRACE_(icon)("(%04x, %04x)\n", handle, flags );
1251 /* Check whether destroying active cursor */
1253 if ( QUEUE_Current()->cursor == handle )
1255 WARN_(cursor)("Destroying active cursor!\n" );
1256 SetCursor( 0 );
1259 /* Try shared cursor/icon first */
1261 if ( !(flags & CID_NONSHARED) )
1263 INT count = CURSORICON_DelSharedIcon( handle );
1265 if ( count != -1 )
1266 return (flags & CID_WIN32)? TRUE : (count == 0);
1268 /* FIXME: OEM cursors/icons should be recognized */
1271 /* Now assume non-shared cursor/icon */
1273 retv = GlobalFree16( handle );
1274 return (flags & CID_RESOURCE)? retv : TRUE;
1277 /***********************************************************************
1278 * DestroyIcon (USER.457)
1280 BOOL16 WINAPI DestroyIcon16( HICON16 hIcon )
1282 return DestroyIcon32( hIcon, 0 );
1285 /***********************************************************************
1286 * DestroyIcon (USER32.@)
1288 BOOL WINAPI DestroyIcon( HICON hIcon )
1290 return DestroyIcon32( hIcon, CID_WIN32 );
1293 /***********************************************************************
1294 * DestroyCursor (USER.458)
1296 BOOL16 WINAPI DestroyCursor16( HCURSOR16 hCursor )
1298 return DestroyIcon32( hCursor, 0 );
1301 /***********************************************************************
1302 * DestroyCursor (USER32.@)
1304 BOOL WINAPI DestroyCursor( HCURSOR hCursor )
1306 return DestroyIcon32( hCursor, CID_WIN32 );
1310 /***********************************************************************
1311 * DrawIcon (USER.84)
1313 BOOL16 WINAPI DrawIcon16( HDC16 hdc, INT16 x, INT16 y, HICON16 hIcon )
1315 return DrawIcon( hdc, x, y, hIcon );
1319 /***********************************************************************
1320 * DrawIcon (USER32.@)
1322 BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
1324 CURSORICONINFO *ptr;
1325 HDC hMemDC;
1326 HBITMAP hXorBits, hAndBits;
1327 COLORREF oldFg, oldBg;
1329 if (!(ptr = (CURSORICONINFO *)GlobalLock16( hIcon ))) return FALSE;
1330 if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
1331 hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1,
1332 (char *)(ptr+1) );
1333 hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
1334 ptr->bBitsPerPixel, (char *)(ptr + 1)
1335 + ptr->nHeight * get_bitmap_width_bytes(ptr->nWidth,1) );
1336 oldFg = SetTextColor( hdc, RGB(0,0,0) );
1337 oldBg = SetBkColor( hdc, RGB(255,255,255) );
1339 if (hXorBits && hAndBits)
1341 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1342 BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
1343 SelectObject( hMemDC, hXorBits );
1344 BitBlt(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
1345 SelectObject( hMemDC, hBitTemp );
1347 DeleteDC( hMemDC );
1348 if (hXorBits) DeleteObject( hXorBits );
1349 if (hAndBits) DeleteObject( hAndBits );
1350 GlobalUnlock16( hIcon );
1351 SetTextColor( hdc, oldFg );
1352 SetBkColor( hdc, oldBg );
1353 return TRUE;
1357 /***********************************************************************
1358 * IconSize (USER.86)
1360 * See "Undocumented Windows". Used by W2.0 paint.exe.
1362 DWORD WINAPI IconSize16( void )
1364 return MAKELONG(GetSystemMetrics(SM_CYICON), GetSystemMetrics(SM_CXICON));
1368 /***********************************************************************
1369 * DumpIcon (USER.459)
1371 DWORD WINAPI DumpIcon16( SEGPTR pInfo, WORD *lpLen,
1372 SEGPTR *lpXorBits, SEGPTR *lpAndBits )
1374 CURSORICONINFO *info = MapSL( pInfo );
1375 int sizeAnd, sizeXor;
1377 if (!info) return 0;
1378 sizeXor = info->nHeight * info->nWidthBytes;
1379 sizeAnd = info->nHeight * get_bitmap_width_bytes( info->nWidth, 1 );
1380 if (lpAndBits) *lpAndBits = pInfo + sizeof(CURSORICONINFO);
1381 if (lpXorBits) *lpXorBits = pInfo + sizeof(CURSORICONINFO) + sizeAnd;
1382 if (lpLen) *lpLen = sizeof(CURSORICONINFO) + sizeAnd + sizeXor;
1383 return MAKELONG( sizeXor, sizeXor );
1387 /***********************************************************************
1388 * SetCursor (USER.69)
1390 HCURSOR16 WINAPI SetCursor16( HCURSOR16 hCursor )
1392 return (HCURSOR16)SetCursor( hCursor );
1396 /***********************************************************************
1397 * SetCursor (USER32.@)
1398 * RETURNS:
1399 * A handle to the previous cursor shape.
1401 HCURSOR WINAPI SetCursor( HCURSOR hCursor /* [in] Handle of cursor to show */ )
1403 MESSAGEQUEUE *queue = QUEUE_Current();
1404 HCURSOR hOldCursor;
1406 if (hCursor == queue->cursor) return hCursor; /* No change */
1407 TRACE_(cursor)("%04x\n", hCursor );
1408 hOldCursor = queue->cursor;
1409 queue->cursor = hCursor;
1410 /* Change the cursor shape only if it is visible */
1411 if (queue->cursor_count >= 0)
1413 USER_Driver.pSetCursor( (CURSORICONINFO*)GlobalLock16( hCursor ) );
1414 GlobalUnlock16( hCursor );
1416 return hOldCursor;
1420 /***********************************************************************
1421 * ShowCursor (USER.71)
1423 INT16 WINAPI ShowCursor16( BOOL16 bShow )
1425 return ShowCursor( bShow );
1429 /***********************************************************************
1430 * ShowCursor (USER32.@)
1432 INT WINAPI ShowCursor( BOOL bShow )
1434 MESSAGEQUEUE *queue = QUEUE_Current();
1436 TRACE_(cursor)("%d, count=%d\n", bShow, queue->cursor_count );
1438 if (bShow)
1440 if (++queue->cursor_count == 0) /* Show it */
1442 USER_Driver.pSetCursor( (CURSORICONINFO*)GlobalLock16( queue->cursor ) );
1443 GlobalUnlock16( queue->cursor );
1446 else
1448 if (--queue->cursor_count == -1) /* Hide it */
1449 USER_Driver.pSetCursor( NULL );
1451 return queue->cursor_count;
1455 /***********************************************************************
1456 * GetCursor (USER.247)
1458 HCURSOR16 WINAPI GetCursor16(void)
1460 return GetCursor();
1464 /***********************************************************************
1465 * GetCursor (USER32.@)
1467 HCURSOR WINAPI GetCursor(void)
1469 return QUEUE_Current()->cursor;
1473 /***********************************************************************
1474 * ClipCursor (USER.16)
1476 BOOL16 WINAPI ClipCursor16( const RECT16 *rect )
1478 if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1479 else CONV_RECT16TO32( rect, &CURSOR_ClipRect );
1480 return TRUE;
1484 /***********************************************************************
1485 * ClipCursor (USER32.@)
1487 BOOL WINAPI ClipCursor( const RECT *rect )
1489 if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1490 else CopyRect( &CURSOR_ClipRect, rect );
1491 return TRUE;
1495 /***********************************************************************
1496 * GetClipCursor (USER.309)
1498 void WINAPI GetClipCursor16( RECT16 *rect )
1500 if (rect) CONV_RECT32TO16( &CURSOR_ClipRect, rect );
1504 /***********************************************************************
1505 * GetClipCursor (USER32.@)
1507 BOOL WINAPI GetClipCursor( RECT *rect )
1509 if (rect)
1511 CopyRect( rect, &CURSOR_ClipRect );
1512 return TRUE;
1514 return FALSE;
1517 /**********************************************************************
1518 * LookupIconIdFromDirectoryEx (USER.364)
1520 * FIXME: exact parameter sizes
1522 INT16 WINAPI LookupIconIdFromDirectoryEx16( LPBYTE xdir, BOOL16 bIcon,
1523 INT16 width, INT16 height, UINT16 cFlag )
1525 CURSORICONDIR *dir = (CURSORICONDIR*)xdir;
1526 UINT16 retVal = 0;
1527 if( dir && !dir->idReserved && (dir->idType & 3) )
1529 CURSORICONDIRENTRY* entry;
1530 HDC hdc;
1531 UINT palEnts;
1532 int colors;
1533 hdc = GetDC(0);
1534 palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
1535 if (palEnts == 0)
1536 palEnts = 256;
1537 colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
1539 ReleaseDC(0, hdc);
1541 if( bIcon )
1542 entry = CURSORICON_FindBestIcon( dir, width, height, colors );
1543 else
1544 entry = CURSORICON_FindBestCursor( dir, width, height, 1);
1546 if( entry ) retVal = entry->wResId;
1548 else WARN_(cursor)("invalid resource directory\n");
1549 return retVal;
1552 /**********************************************************************
1553 * LookupIconIdFromDirectoryEx (USER32.@)
1555 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE dir, BOOL bIcon,
1556 INT width, INT height, UINT cFlag )
1558 return LookupIconIdFromDirectoryEx16( dir, bIcon, width, height, cFlag );
1561 /**********************************************************************
1562 * LookupIconIdFromDirectory (USER.?)
1564 INT16 WINAPI LookupIconIdFromDirectory16( LPBYTE dir, BOOL16 bIcon )
1566 return LookupIconIdFromDirectoryEx16( dir, bIcon,
1567 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1568 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1571 /**********************************************************************
1572 * LookupIconIdFromDirectory (USER32.@)
1574 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1576 return LookupIconIdFromDirectoryEx( dir, bIcon,
1577 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1578 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1581 /**********************************************************************
1582 * GetIconID (USER.455)
1584 WORD WINAPI GetIconID16( HGLOBAL16 hResource, DWORD resType )
1586 LPBYTE lpDir = (LPBYTE)GlobalLock16(hResource);
1588 TRACE_(cursor)("hRes=%04x, entries=%i\n",
1589 hResource, lpDir ? ((CURSORICONDIR*)lpDir)->idCount : 0);
1591 switch(resType)
1593 case RT_CURSOR16:
1594 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, FALSE,
1595 GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1596 case RT_ICON16:
1597 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, TRUE,
1598 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0 );
1599 default:
1600 WARN_(cursor)("invalid res type %ld\n", resType );
1602 return 0;
1605 /**********************************************************************
1606 * LoadCursorIconHandler (USER.336)
1608 * Supposed to load resources of Windows 2.x applications.
1610 HGLOBAL16 WINAPI LoadCursorIconHandler16( HGLOBAL16 hResource, HMODULE16 hModule, HRSRC16 hRsrc )
1612 FIXME_(cursor)("(%04x,%04x,%04x): old 2.x resources are not supported!\n",
1613 hResource, hModule, hRsrc);
1614 return (HGLOBAL16)0;
1617 /**********************************************************************
1618 * LoadDIBIconHandler (USER.357)
1620 * RT_ICON resource loader, installed by USER_SignalProc when module
1621 * is initialized.
1623 HGLOBAL16 WINAPI LoadDIBIconHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1625 /* If hResource is zero we must allocate a new memory block, if it's
1626 * non-zero but GlobalLock() returns NULL then it was discarded and
1627 * we have to recommit some memory, otherwise we just need to check
1628 * the block size. See LoadProc() in 16-bit SDK for more.
1631 hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1632 if( hMemObj )
1634 LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1635 hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1636 SizeofResource16(hModule, hRsrc), TRUE, 0x00030000,
1637 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR );
1639 return hMemObj;
1642 /**********************************************************************
1643 * LoadDIBCursorHandler (USER.356)
1645 * RT_CURSOR resource loader. Same as above.
1647 HGLOBAL16 WINAPI LoadDIBCursorHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1649 hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1650 if( hMemObj )
1652 LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1653 hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1654 SizeofResource16(hModule, hRsrc), FALSE, 0x00030000,
1655 GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1657 return hMemObj;
1660 /**********************************************************************
1661 * LoadIconHandler (USER.456)
1663 HICON16 WINAPI LoadIconHandler16( HGLOBAL16 hResource, BOOL16 bNew )
1665 LPBYTE bits = (LPBYTE)LockResource16( hResource );
1667 TRACE_(cursor)("hRes=%04x\n",hResource);
1669 return CURSORICON_CreateFromResource( 0, 0, bits, 0, TRUE,
1670 bNew ? 0x00030000 : 0x00020000, 0, 0, LR_DEFAULTCOLOR );
1673 /***********************************************************************
1674 * LoadCursorW (USER32.@)
1676 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
1678 return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0,
1679 LR_SHARED | LR_DEFAULTSIZE );
1682 /***********************************************************************
1683 * LoadCursorA (USER32.@)
1685 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
1687 return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0,
1688 LR_SHARED | LR_DEFAULTSIZE );
1691 /***********************************************************************
1692 * LoadCursorFromFileW (USER32.@)
1694 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
1696 return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0,
1697 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1700 /***********************************************************************
1701 * LoadCursorFromFileA (USER32.@)
1703 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR 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 return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0,
1715 LR_SHARED | LR_DEFAULTSIZE );
1718 /***********************************************************************
1719 * LoadIconA (USER32.@)
1721 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
1723 return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0,
1724 LR_SHARED | LR_DEFAULTSIZE );
1727 /**********************************************************************
1728 * GetIconInfo (USER.395)
1730 BOOL16 WINAPI GetIconInfo16(HICON16 hIcon,LPICONINFO16 iconinfo)
1732 ICONINFO ii32;
1733 BOOL16 ret = GetIconInfo((HICON)hIcon, &ii32);
1735 iconinfo->fIcon = ii32.fIcon;
1736 iconinfo->xHotspot = ii32.xHotspot;
1737 iconinfo->yHotspot = ii32.yHotspot;
1738 iconinfo->hbmMask = ii32.hbmMask;
1739 iconinfo->hbmColor = ii32.hbmColor;
1740 return ret;
1743 /**********************************************************************
1744 * GetIconInfo (USER32.@)
1746 BOOL WINAPI GetIconInfo(HICON hIcon,PICONINFO iconinfo) {
1747 CURSORICONINFO *ciconinfo;
1749 ciconinfo = GlobalLock16(hIcon);
1750 if (!ciconinfo)
1751 return FALSE;
1753 if ( (ciconinfo->ptHotSpot.x == ICON_HOTSPOT) &&
1754 (ciconinfo->ptHotSpot.y == ICON_HOTSPOT) )
1756 iconinfo->fIcon = TRUE;
1757 iconinfo->xHotspot = ciconinfo->nWidth / 2;
1758 iconinfo->yHotspot = ciconinfo->nHeight / 2;
1760 else
1762 iconinfo->fIcon = FALSE;
1763 iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
1764 iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
1767 iconinfo->hbmColor = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1768 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
1769 (char *)(ciconinfo + 1)
1770 + ciconinfo->nHeight *
1771 get_bitmap_width_bytes (ciconinfo->nWidth,1) );
1772 iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1773 1, 1, (char *)(ciconinfo + 1));
1775 GlobalUnlock16(hIcon);
1777 return TRUE;
1780 /**********************************************************************
1781 * CreateIconIndirect (USER32.@)
1783 HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
1785 BITMAP bmpXor,bmpAnd;
1786 HICON hObj;
1787 int sizeXor,sizeAnd;
1789 GetObjectA( iconinfo->hbmColor, sizeof(bmpXor), &bmpXor );
1790 GetObjectA( iconinfo->hbmMask, sizeof(bmpAnd), &bmpAnd );
1792 sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
1793 sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
1795 hObj = GlobalAlloc16( GMEM_MOVEABLE,
1796 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
1797 if (hObj)
1799 CURSORICONINFO *info;
1801 info = (CURSORICONINFO *)GlobalLock16( hObj );
1803 /* If we are creating an icon, the hotspot is unused */
1804 if (iconinfo->fIcon)
1806 info->ptHotSpot.x = ICON_HOTSPOT;
1807 info->ptHotSpot.y = ICON_HOTSPOT;
1809 else
1811 info->ptHotSpot.x = iconinfo->xHotspot;
1812 info->ptHotSpot.y = iconinfo->yHotspot;
1815 info->nWidth = bmpXor.bmWidth;
1816 info->nHeight = bmpXor.bmHeight;
1817 info->nWidthBytes = bmpXor.bmWidthBytes;
1818 info->bPlanes = bmpXor.bmPlanes;
1819 info->bBitsPerPixel = bmpXor.bmBitsPixel;
1821 /* Transfer the bitmap bits to the CURSORICONINFO structure */
1823 GetBitmapBits( iconinfo->hbmMask ,sizeAnd,(char*)(info + 1) );
1824 GetBitmapBits( iconinfo->hbmColor,sizeXor,(char*)(info + 1) +sizeAnd);
1825 GlobalUnlock16( hObj );
1827 return hObj;
1831 /**********************************************************************
1832 * DrawIconEx (USER.394)
1834 BOOL16 WINAPI DrawIconEx16 (HDC16 hdc, INT16 xLeft, INT16 yTop, HICON16 hIcon,
1835 INT16 cxWidth, INT16 cyWidth, UINT16 istep,
1836 HBRUSH16 hbr, UINT16 flags)
1838 return DrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
1839 istep, hbr, flags);
1843 /******************************************************************************
1844 * DrawIconEx (USER32.@) Draws an icon or cursor on device context
1846 * NOTES
1847 * Why is this using SM_CXICON instead of SM_CXCURSOR?
1849 * PARAMS
1850 * hdc [I] Handle to device context
1851 * x0 [I] X coordinate of upper left corner
1852 * y0 [I] Y coordinate of upper left corner
1853 * hIcon [I] Handle to icon to draw
1854 * cxWidth [I] Width of icon
1855 * cyWidth [I] Height of icon
1856 * istep [I] Index of frame in animated cursor
1857 * hbr [I] Handle to background brush
1858 * flags [I] Icon-drawing flags
1860 * RETURNS
1861 * Success: TRUE
1862 * Failure: FALSE
1864 BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
1865 INT cxWidth, INT cyWidth, UINT istep,
1866 HBRUSH hbr, UINT flags )
1868 CURSORICONINFO *ptr = (CURSORICONINFO *)GlobalLock16 (hIcon);
1869 HDC hDC_off = 0, hMemDC = CreateCompatibleDC (hdc);
1870 BOOL result = FALSE, DoOffscreen;
1871 HBITMAP hB_off = 0, hOld = 0;
1873 if (!ptr) return FALSE;
1874 TRACE_(icon)("(hdc=%x,pos=%d.%d,hicon=%x,extend=%d.%d,istep=%d,br=%x,flags=0x%08x)\n",
1875 hdc,x0,y0,hIcon,cxWidth,cyWidth,istep,hbr,flags
1878 if (istep)
1879 FIXME_(icon)("Ignoring istep=%d\n", istep);
1880 if (flags & DI_COMPAT)
1881 FIXME_(icon)("Ignoring flag DI_COMPAT\n");
1883 if (!flags) {
1884 FIXME_(icon)("no flags set? setting to DI_NORMAL\n");
1885 flags = DI_NORMAL;
1888 /* Calculate the size of the destination image. */
1889 if (cxWidth == 0)
1891 if (flags & DI_DEFAULTSIZE)
1892 cxWidth = GetSystemMetrics (SM_CXICON);
1893 else
1894 cxWidth = ptr->nWidth;
1896 if (cyWidth == 0)
1898 if (flags & DI_DEFAULTSIZE)
1899 cyWidth = GetSystemMetrics (SM_CYICON);
1900 else
1901 cyWidth = ptr->nHeight;
1904 DoOffscreen = (GetObjectType( hbr ) == OBJ_BRUSH);
1906 if (DoOffscreen) {
1907 RECT r;
1909 r.left = 0;
1910 r.top = 0;
1911 r.right = cxWidth;
1912 r.bottom = cxWidth;
1914 hDC_off = CreateCompatibleDC(hdc);
1915 hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth);
1916 if (hDC_off && hB_off) {
1917 hOld = SelectObject(hDC_off, hB_off);
1918 FillRect(hDC_off, &r, hbr);
1922 if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
1924 HBITMAP hXorBits, hAndBits;
1925 COLORREF oldFg, oldBg;
1926 INT nStretchMode;
1928 nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
1930 hXorBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1931 ptr->bPlanes, ptr->bBitsPerPixel,
1932 (char *)(ptr + 1)
1933 + ptr->nHeight *
1934 get_bitmap_width_bytes(ptr->nWidth,1) );
1935 hAndBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1936 1, 1, (char *)(ptr+1) );
1937 oldFg = SetTextColor( hdc, RGB(0,0,0) );
1938 oldBg = SetBkColor( hdc, RGB(255,255,255) );
1940 if (hXorBits && hAndBits)
1942 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1943 if (flags & DI_MASK)
1945 if (DoOffscreen)
1946 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1947 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1948 else
1949 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
1950 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1952 SelectObject( hMemDC, hXorBits );
1953 if (flags & DI_IMAGE)
1955 if (DoOffscreen)
1956 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1957 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
1958 else
1959 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
1960 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
1962 SelectObject( hMemDC, hBitTemp );
1963 result = TRUE;
1966 SetTextColor( hdc, oldFg );
1967 SetBkColor( hdc, oldBg );
1968 if (hXorBits) DeleteObject( hXorBits );
1969 if (hAndBits) DeleteObject( hAndBits );
1970 SetStretchBltMode (hdc, nStretchMode);
1971 if (DoOffscreen) {
1972 BitBlt(hdc, x0, y0, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
1973 SelectObject(hDC_off, hOld);
1976 if (hMemDC) DeleteDC( hMemDC );
1977 if (hDC_off) DeleteDC(hDC_off);
1978 if (hB_off) DeleteObject(hB_off);
1979 GlobalUnlock16( hIcon );
1980 return result;
1983 /***********************************************************************
1984 * DIB_FixColorsToLoadflags
1986 * Change color table entries when LR_LOADTRANSPARENT or LR_LOADMAP3DCOLORS
1987 * are in loadflags
1989 static void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags, BYTE pix)
1991 int colors;
1992 COLORREF c_W, c_S, c_F, c_L, c_C;
1993 int incr,i;
1994 RGBQUAD *ptr;
1996 if (bmi->bmiHeader.biBitCount > 8) return;
1997 if (bmi->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)) incr = 4;
1998 else if (bmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) incr = 3;
1999 else {
2000 WARN_(resource)("Wrong bitmap header size!\n");
2001 return;
2003 colors = bmi->bmiHeader.biClrUsed;
2004 if (!colors && (bmi->bmiHeader.biBitCount <= 8))
2005 colors = 1 << bmi->bmiHeader.biBitCount;
2006 c_W = GetSysColor(COLOR_WINDOW);
2007 c_S = GetSysColor(COLOR_3DSHADOW);
2008 c_F = GetSysColor(COLOR_3DFACE);
2009 c_L = GetSysColor(COLOR_3DLIGHT);
2010 if (loadflags & LR_LOADTRANSPARENT) {
2011 switch (bmi->bmiHeader.biBitCount) {
2012 case 1: pix = pix >> 7; break;
2013 case 4: pix = pix >> 4; break;
2014 case 8: break;
2015 default:
2016 WARN_(resource)("(%d): Unsupported depth\n", bmi->bmiHeader.biBitCount);
2017 return;
2019 if (pix >= colors) {
2020 WARN_(resource)("pixel has color index greater than biClrUsed!\n");
2021 return;
2023 if (loadflags & LR_LOADMAP3DCOLORS) c_W = c_F;
2024 ptr = (RGBQUAD*)((char*)bmi->bmiColors+pix*incr);
2025 ptr->rgbBlue = GetBValue(c_W);
2026 ptr->rgbGreen = GetGValue(c_W);
2027 ptr->rgbRed = GetRValue(c_W);
2029 if (loadflags & LR_LOADMAP3DCOLORS)
2030 for (i=0; i<colors; i++) {
2031 ptr = (RGBQUAD*)((char*)bmi->bmiColors+i*incr);
2032 c_C = RGB(ptr->rgbRed, ptr->rgbGreen, ptr->rgbBlue);
2033 if (c_C == RGB(128, 128, 128)) {
2034 ptr->rgbRed = GetRValue(c_S);
2035 ptr->rgbGreen = GetGValue(c_S);
2036 ptr->rgbBlue = GetBValue(c_S);
2037 } else if (c_C == RGB(192, 192, 192)) {
2038 ptr->rgbRed = GetRValue(c_F);
2039 ptr->rgbGreen = GetGValue(c_F);
2040 ptr->rgbBlue = GetBValue(c_F);
2041 } else if (c_C == RGB(223, 223, 223)) {
2042 ptr->rgbRed = GetRValue(c_L);
2043 ptr->rgbGreen = GetGValue(c_L);
2044 ptr->rgbBlue = GetBValue(c_L);
2050 /**********************************************************************
2051 * BITMAP_Load
2053 static HBITMAP BITMAP_Load( HINSTANCE instance,LPCWSTR name, UINT loadflags )
2055 HBITMAP hbitmap = 0;
2056 HRSRC hRsrc;
2057 HGLOBAL handle;
2058 char *ptr = NULL;
2059 BITMAPINFO *info, *fix_info=NULL;
2060 HGLOBAL hFix;
2061 int size;
2063 if (!(loadflags & LR_LOADFROMFILE))
2065 if (!instance)
2067 /* OEM bitmap: try to load the resource from user32.dll */
2068 if (HIWORD(name)) return 0;
2069 if (!(instance = GetModuleHandleA("user32.dll"))) return 0;
2071 if (!(hRsrc = FindResourceW( instance, name, RT_BITMAPW ))) return 0;
2072 if (!(handle = LoadResource( instance, hRsrc ))) return 0;
2074 if ((info = (BITMAPINFO *)LockResource( handle )) == NULL) return 0;
2076 else
2078 if (!(ptr = map_fileW( name ))) return 0;
2079 info = (BITMAPINFO *)(ptr + sizeof(BITMAPFILEHEADER));
2081 size = DIB_BitmapInfoSize(info, DIB_RGB_COLORS);
2082 if ((hFix = GlobalAlloc(0, size))) fix_info=GlobalLock(hFix);
2083 if (fix_info) {
2084 BYTE pix;
2086 memcpy(fix_info, info, size);
2087 pix = *((LPBYTE)info+DIB_BitmapInfoSize(info, DIB_RGB_COLORS));
2088 DIB_FixColorsToLoadflags(fix_info, loadflags, pix);
2089 if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
2090 if (screen_dc)
2092 char *bits = (char *)info + size;
2093 if (loadflags & LR_CREATEDIBSECTION) {
2094 DIBSECTION dib;
2095 hbitmap = CreateDIBSection(screen_dc, fix_info, DIB_RGB_COLORS, NULL, 0, 0);
2096 GetObjectA(hbitmap, sizeof(DIBSECTION), &dib);
2097 SetDIBits(screen_dc, hbitmap, 0, dib.dsBm.bmHeight, bits, info,
2098 DIB_RGB_COLORS);
2100 else {
2101 hbitmap = CreateDIBitmap( screen_dc, &fix_info->bmiHeader, CBM_INIT,
2102 bits, fix_info, DIB_RGB_COLORS );
2105 GlobalUnlock(hFix);
2106 GlobalFree(hFix);
2108 if (loadflags & LR_LOADFROMFILE) UnmapViewOfFile( ptr );
2109 return hbitmap;
2113 /***********************************************************************
2114 * LoadImage (USER.389)
2117 HANDLE16 WINAPI LoadImage16( HINSTANCE16 hinst, LPCSTR name, UINT16 type,
2118 INT16 desiredx, INT16 desiredy, UINT16 loadflags)
2120 return LoadImageA( hinst, name, type, desiredx, desiredy, loadflags );
2123 /**********************************************************************
2124 * LoadImageA (USER32.@)
2126 * FIXME: implementation lacks some features, see LR_ defines in winuser.h
2129 /* filter for page-fault exceptions */
2130 static WINE_EXCEPTION_FILTER(page_fault)
2132 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
2133 return EXCEPTION_EXECUTE_HANDLER;
2134 return EXCEPTION_CONTINUE_SEARCH;
2137 /*********************************************************************/
2139 HANDLE WINAPI LoadImageA( HINSTANCE hinst, LPCSTR name, UINT type,
2140 INT desiredx, INT desiredy, UINT loadflags)
2142 HANDLE res;
2143 LPWSTR u_name;
2145 if (!HIWORD(name))
2146 return LoadImageW(hinst, (LPWSTR)name, type, desiredx, desiredy, loadflags);
2148 __TRY {
2149 DWORD len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
2150 u_name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2151 MultiByteToWideChar( CP_ACP, 0, name, -1, u_name, len );
2153 __EXCEPT(page_fault) {
2154 SetLastError( ERROR_INVALID_PARAMETER );
2155 return 0;
2157 __ENDTRY
2158 res = LoadImageW(hinst, u_name, type, desiredx, desiredy, loadflags);
2159 HeapFree(GetProcessHeap(), 0, u_name);
2160 return res;
2164 /******************************************************************************
2165 * LoadImageW (USER32.@) Loads an icon, cursor, or bitmap
2167 * PARAMS
2168 * hinst [I] Handle of instance that contains image
2169 * name [I] Name of image
2170 * type [I] Type of image
2171 * desiredx [I] Desired width
2172 * desiredy [I] Desired height
2173 * loadflags [I] Load flags
2175 * RETURNS
2176 * Success: Handle to newly loaded image
2177 * Failure: NULL
2179 * FIXME: Implementation lacks some features, see LR_ defines in winuser.h
2181 HANDLE WINAPI LoadImageW( HINSTANCE hinst, LPCWSTR name, UINT type,
2182 INT desiredx, INT desiredy, UINT loadflags )
2184 if (HIWORD(name)) {
2185 TRACE_(resource)("(0x%04x,%p,%d,%d,%d,0x%08x)\n",
2186 hinst,name,type,desiredx,desiredy,loadflags);
2187 } else {
2188 TRACE_(resource)("(0x%04x,%p,%d,%d,%d,0x%08x)\n",
2189 hinst,name,type,desiredx,desiredy,loadflags);
2191 if (loadflags & LR_DEFAULTSIZE) {
2192 if (type == IMAGE_ICON) {
2193 if (!desiredx) desiredx = GetSystemMetrics(SM_CXICON);
2194 if (!desiredy) desiredy = GetSystemMetrics(SM_CYICON);
2195 } else if (type == IMAGE_CURSOR) {
2196 if (!desiredx) desiredx = GetSystemMetrics(SM_CXCURSOR);
2197 if (!desiredy) desiredy = GetSystemMetrics(SM_CYCURSOR);
2200 if (loadflags & LR_LOADFROMFILE) loadflags &= ~LR_SHARED;
2201 switch (type) {
2202 case IMAGE_BITMAP:
2203 return BITMAP_Load( hinst, name, loadflags );
2205 case IMAGE_ICON:
2206 if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
2207 if (screen_dc)
2209 UINT palEnts = GetSystemPaletteEntries(screen_dc, 0, 0, NULL);
2210 if (palEnts == 0) palEnts = 256;
2211 return CURSORICON_Load(hinst, name, desiredx, desiredy,
2212 palEnts, FALSE, loadflags);
2214 break;
2216 case IMAGE_CURSOR:
2217 return CURSORICON_Load(hinst, name, desiredx, desiredy,
2218 1, TRUE, loadflags);
2220 return 0;
2224 /******************************************************************************
2225 * CopyImage (USER.390) Creates new image and copies attributes to it
2228 HICON16 WINAPI CopyImage16( HANDLE16 hnd, UINT16 type, INT16 desiredx,
2229 INT16 desiredy, UINT16 flags )
2231 return (HICON16)CopyImage((HANDLE)hnd, (UINT)type, (INT)desiredx,
2232 (INT)desiredy, (UINT)flags);
2235 /******************************************************************************
2236 * CopyImage (USER32.@) Creates new image and copies attributes to it
2238 * PARAMS
2239 * hnd [I] Handle to image to copy
2240 * type [I] Type of image to copy
2241 * desiredx [I] Desired width of new image
2242 * desiredy [I] Desired height of new image
2243 * flags [I] Copy flags
2245 * RETURNS
2246 * Success: Handle to newly created image
2247 * Failure: NULL
2249 * FIXME: implementation still lacks nearly all features, see LR_*
2250 * defines in winuser.h
2252 HICON WINAPI CopyImage( HANDLE hnd, UINT type, INT desiredx,
2253 INT desiredy, UINT flags )
2255 switch (type)
2257 case IMAGE_BITMAP:
2259 HBITMAP res;
2260 BITMAP bm;
2262 if (!GetObjectW( hnd, sizeof(bm), &bm )) return 0;
2263 bm.bmBits = NULL;
2264 if ((res = CreateBitmapIndirect(&bm)))
2266 char *buf = HeapAlloc( GetProcessHeap(), 0, bm.bmWidthBytes * bm.bmHeight );
2267 GetBitmapBits( hnd, bm.bmWidthBytes * bm.bmHeight, buf );
2268 SetBitmapBits( res, bm.bmWidthBytes * bm.bmHeight, buf );
2269 HeapFree( GetProcessHeap(), 0, buf );
2271 return res;
2273 case IMAGE_ICON:
2274 return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags);
2275 case IMAGE_CURSOR:
2276 /* Should call CURSORICON_ExtCopy but more testing
2277 * needs to be done before we change this
2279 return CopyCursor(hnd);
2281 return 0;
2285 /******************************************************************************
2286 * LoadBitmapW (USER32.@) Loads bitmap from the executable file
2288 * RETURNS
2289 * Success: Handle to specified bitmap
2290 * Failure: NULL
2292 HBITMAP WINAPI LoadBitmapW(
2293 HINSTANCE instance, /* [in] Handle to application instance */
2294 LPCWSTR name) /* [in] Address of bitmap resource name */
2296 return LoadImageW( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2299 /**********************************************************************
2300 * LoadBitmapA (USER32.@)
2302 HBITMAP WINAPI LoadBitmapA( HINSTANCE instance, LPCSTR name )
2304 return LoadImageA( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2307 /**********************************************************************
2308 * LoadBitmap (USER.175)
2310 HBITMAP16 WINAPI LoadBitmap16( HINSTANCE16 instance, LPCSTR name )
2312 return LoadBitmapA( instance, name );