Add decoding logic for VGA indexed registers.
[wine/multimedia.git] / windows / cursoricon.c
blob8315233f2a01fcfd773d2b078ae2a11897ddb0cd
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_DECLARE_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 * CURSORICON_FindSharedIcon
129 static HANDLE CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
131 HANDLE handle = 0;
132 ICONCACHE *ptr;
134 EnterCriticalSection( &IconCrst );
136 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
137 if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
139 ptr->count++;
140 handle = ptr->handle;
141 break;
144 LeaveCriticalSection( &IconCrst );
146 return handle;
149 /*************************************************************************
150 * CURSORICON_FindCache
152 * Given a handle, find the corresponding cache element
154 * PARAMS
155 * Handle [I] handle to an Image
157 * RETURNS
158 * Success: The cache entry
159 * Failure: NULL
162 static ICONCACHE* CURSORICON_FindCache(HANDLE handle)
164 ICONCACHE *ptr;
165 ICONCACHE *pRet=NULL;
166 BOOL IsFound = FALSE;
167 int count;
169 EnterCriticalSection( &IconCrst );
171 for (count = 0, ptr = IconAnchor; ptr != NULL && !IsFound; ptr = ptr->next, count++ )
173 if ( handle == ptr->handle )
175 IsFound = TRUE;
176 pRet = ptr;
180 LeaveCriticalSection( &IconCrst );
182 return pRet;
185 /**********************************************************************
186 * CURSORICON_AddSharedIcon
188 static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HRSRC hGroupRsrc, HANDLE handle )
190 ICONCACHE *ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(ICONCACHE) );
191 if ( !ptr ) return;
193 ptr->hModule = hModule;
194 ptr->hRsrc = hRsrc;
195 ptr->handle = handle;
196 ptr->hGroupRsrc = hGroupRsrc;
197 ptr->count = 1;
199 EnterCriticalSection( &IconCrst );
200 ptr->next = IconAnchor;
201 IconAnchor = ptr;
202 LeaveCriticalSection( &IconCrst );
205 /**********************************************************************
206 * CURSORICON_DelSharedIcon
208 static INT CURSORICON_DelSharedIcon( HANDLE handle )
210 INT count = -1;
211 ICONCACHE *ptr;
213 EnterCriticalSection( &IconCrst );
215 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
216 if ( ptr->handle == handle )
218 if ( ptr->count > 0 ) ptr->count--;
219 count = ptr->count;
220 break;
223 LeaveCriticalSection( &IconCrst );
225 return count;
228 /**********************************************************************
229 * CURSORICON_FreeModuleIcons
231 void CURSORICON_FreeModuleIcons( HMODULE hModule )
233 ICONCACHE **ptr = &IconAnchor;
235 if ( HIWORD( hModule ) )
236 hModule = MapHModuleLS( hModule );
237 else
238 hModule = GetExePtr( hModule );
240 EnterCriticalSection( &IconCrst );
242 while ( *ptr )
244 if ( (*ptr)->hModule == hModule )
246 ICONCACHE *freePtr = *ptr;
247 *ptr = freePtr->next;
249 GlobalFree16( freePtr->handle );
250 HeapFree( GetProcessHeap(), 0, freePtr );
251 continue;
253 ptr = &(*ptr)->next;
256 LeaveCriticalSection( &IconCrst );
259 /**********************************************************************
260 * CURSORICON_FindBestIcon
262 * Find the icon closest to the requested size and number of colors.
264 static CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
265 int height, int colors )
267 int i;
268 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
269 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
270 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
272 if (dir->idCount < 1)
274 WARN_(icon)("Empty directory!\n" );
275 return NULL;
277 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
279 /* Find Best Fit */
280 iTotalDiff = 0xFFFFFFFF;
281 iColorDiff = 0xFFFFFFFF;
282 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
284 iTempXDiff = abs(width - entry->ResInfo.icon.bWidth);
285 iTempYDiff = abs(height - entry->ResInfo.icon.bHeight);
287 if(iTotalDiff > (iTempXDiff + iTempYDiff))
289 iXDiff = iTempXDiff;
290 iYDiff = iTempYDiff;
291 iTotalDiff = iXDiff + iYDiff;
295 /* Find Best Colors for Best Fit */
296 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
298 if(abs(width - entry->ResInfo.icon.bWidth) == iXDiff &&
299 abs(height - entry->ResInfo.icon.bHeight) == iYDiff)
301 iTempColorDiff = abs(colors - entry->ResInfo.icon.bColorCount);
302 if(iColorDiff > iTempColorDiff)
304 bestEntry = entry;
305 iColorDiff = iTempColorDiff;
310 return bestEntry;
314 /**********************************************************************
315 * CURSORICON_FindBestCursor
317 * Find the cursor closest to the requested size.
318 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
319 * ignored too
321 static CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
322 int width, int height, int color)
324 int i, maxwidth, maxheight;
325 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
327 if (dir->idCount < 1)
329 WARN_(cursor)("Empty directory!\n" );
330 return NULL;
332 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
334 /* Double height to account for AND and XOR masks */
336 height *= 2;
338 /* First find the largest one smaller than or equal to the requested size*/
340 maxwidth = maxheight = 0;
341 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
342 if ((entry->ResInfo.cursor.wWidth <= width) && (entry->ResInfo.cursor.wHeight <= height) &&
343 (entry->ResInfo.cursor.wWidth > maxwidth) && (entry->ResInfo.cursor.wHeight > maxheight) &&
344 (entry->wBitCount == 1))
346 bestEntry = entry;
347 maxwidth = entry->ResInfo.cursor.wWidth;
348 maxheight = entry->ResInfo.cursor.wHeight;
350 if (bestEntry) return bestEntry;
352 /* Now find the smallest one larger than the requested size */
354 maxwidth = maxheight = 255;
355 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
356 if ((entry->ResInfo.cursor.wWidth < maxwidth) && (entry->ResInfo.cursor.wHeight < maxheight) &&
357 (entry->wBitCount == 1))
359 bestEntry = entry;
360 maxwidth = entry->ResInfo.cursor.wWidth;
361 maxheight = entry->ResInfo.cursor.wHeight;
364 return bestEntry;
367 /*********************************************************************
368 * The main purpose of this function is to create fake resource directory
369 * and fake resource entries. There are several reasons for this:
370 * - CURSORICONDIR and CURSORICONFILEDIR differ in sizes and their
371 * fields
372 * There are some "bad" cursor files which do not have
373 * bColorCount initialized but instead one must read this info
374 * directly from corresponding DIB sections
375 * Note: wResId is index to array of pointer returned in ptrs (origin is 1)
377 BOOL CURSORICON_SimulateLoadingFromResourceW( LPWSTR filename, BOOL fCursor,
378 CURSORICONDIR **res, LPBYTE **ptr)
380 LPBYTE _free;
381 CURSORICONFILEDIR *bits;
382 int entries, size, i;
384 *res = NULL;
385 *ptr = NULL;
386 if (!(bits = map_fileW( filename ))) return FALSE;
388 /* FIXME: test for inimated icons
389 * hack to load the first icon from the *.ani file
391 if ( *(LPDWORD)bits==0x46464952 ) /* "RIFF" */
392 { LPBYTE pos = (LPBYTE) bits;
393 FIXME_(cursor)("Animated icons not correctly implemented! %p \n", bits);
395 for (;;)
396 { if (*(LPDWORD)pos==0x6e6f6369) /* "icon" */
397 { FIXME_(cursor)("icon entry found! %p\n", bits);
398 pos+=4;
399 if ( !*(LPWORD) pos==0x2fe) /* iconsize */
400 { goto fail;
402 bits=(CURSORICONFILEDIR*)(pos+4);
403 FIXME_(cursor)("icon size ok. offset=%p \n", bits);
404 break;
406 pos+=2;
407 if (pos>=(LPBYTE)bits+766) goto fail;
410 if (!(entries = bits->idCount)) goto fail;
411 size = sizeof(CURSORICONDIR) + sizeof(CURSORICONDIRENTRY) * (entries - 1);
412 _free = (LPBYTE) size;
414 for (i=0; i < entries; i++)
415 size += bits->idEntries[i].dwDIBSize + (fCursor ? sizeof(POINT16): 0);
417 if (!(*ptr = HeapAlloc( GetProcessHeap(), 0,
418 entries * sizeof (CURSORICONDIRENTRY*)))) goto fail;
419 if (!(*res = HeapAlloc( GetProcessHeap(), 0, size))) goto fail;
421 _free = (LPBYTE)(*res) + (int)_free;
422 memcpy((*res), bits, 6);
423 for (i=0; i<entries; i++)
425 ((LPBYTE*)(*ptr))[i] = _free;
426 if (fCursor) {
427 (*res)->idEntries[i].ResInfo.cursor.wWidth=bits->idEntries[i].bWidth;
428 (*res)->idEntries[i].ResInfo.cursor.wHeight=bits->idEntries[i].bHeight;
429 ((LPPOINT16)_free)->x=bits->idEntries[i].xHotspot;
430 ((LPPOINT16)_free)->y=bits->idEntries[i].yHotspot;
431 _free+=sizeof(POINT16);
432 } else {
433 (*res)->idEntries[i].ResInfo.icon.bWidth=bits->idEntries[i].bWidth;
434 (*res)->idEntries[i].ResInfo.icon.bHeight=bits->idEntries[i].bHeight;
435 (*res)->idEntries[i].ResInfo.icon.bColorCount = bits->idEntries[i].bColorCount;
437 (*res)->idEntries[i].wPlanes=1;
438 (*res)->idEntries[i].wBitCount = ((LPBITMAPINFOHEADER)((LPBYTE)bits +
439 bits->idEntries[i].dwDIBOffset))->biBitCount;
440 (*res)->idEntries[i].dwBytesInRes = bits->idEntries[i].dwDIBSize;
441 (*res)->idEntries[i].wResId=i+1;
443 memcpy(_free,(LPBYTE)bits +bits->idEntries[i].dwDIBOffset,
444 (*res)->idEntries[i].dwBytesInRes);
445 _free += (*res)->idEntries[i].dwBytesInRes;
447 UnmapViewOfFile( bits );
448 return TRUE;
449 fail:
450 if (*res) HeapFree( GetProcessHeap(), 0, *res );
451 if (*ptr) HeapFree( GetProcessHeap(), 0, *ptr );
452 UnmapViewOfFile( bits );
453 return FALSE;
457 /**********************************************************************
458 * CURSORICON_CreateFromResource
460 * Create a cursor or icon from in-memory resource template.
462 * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
463 * with cbSize parameter as well.
465 static HGLOBAL16 CURSORICON_CreateFromResource( HINSTANCE16 hInstance, HGLOBAL16 hObj, LPBYTE bits,
466 UINT cbSize, BOOL bIcon, DWORD dwVersion,
467 INT width, INT height, UINT loadflags )
469 static HDC hdcMem;
470 int sizeAnd, sizeXor;
471 HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
472 BITMAP bmpXor, bmpAnd;
473 POINT16 hotspot;
474 BITMAPINFO *bmi;
475 BOOL DoStretch;
476 INT size;
478 hotspot.x = ICON_HOTSPOT;
479 hotspot.y = ICON_HOTSPOT;
481 TRACE_(cursor)("%08x (%u bytes), ver %08x, %ix%i %s %s\n",
482 (unsigned)bits, cbSize, (unsigned)dwVersion, width, height,
483 bIcon ? "icon" : "cursor", (loadflags & LR_MONOCHROME) ? "mono" : "" );
484 if (dwVersion == 0x00020000)
486 FIXME_(cursor)("\t2.xx resources are not supported\n");
487 return 0;
490 if (bIcon)
491 bmi = (BITMAPINFO *)bits;
492 else /* get the hotspot */
494 POINT16 *pt = (POINT16 *)bits;
495 hotspot = *pt;
496 bmi = (BITMAPINFO *)(pt + 1);
498 size = DIB_BitmapInfoSize( bmi, DIB_RGB_COLORS );
500 if (!width) width = bmi->bmiHeader.biWidth;
501 if (!height) height = bmi->bmiHeader.biHeight/2;
502 DoStretch = (bmi->bmiHeader.biHeight/2 != height) ||
503 (bmi->bmiHeader.biWidth != width);
505 /* Check bitmap header */
507 if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
508 (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) ||
509 bmi->bmiHeader.biCompression != BI_RGB) )
511 WARN_(cursor)("\tinvalid resource bitmap header.\n");
512 return 0;
515 if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
516 if (screen_dc)
518 BITMAPINFO* pInfo;
520 /* Make sure we have room for the monochrome bitmap later on.
521 * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
522 * up to and including the biBitCount. In-memory icon resource
523 * format is as follows:
525 * BITMAPINFOHEADER icHeader // DIB header
526 * RGBQUAD icColors[] // Color table
527 * BYTE icXOR[] // DIB bits for XOR mask
528 * BYTE icAND[] // DIB bits for AND mask
531 if ((pInfo = (BITMAPINFO *)HeapAlloc( GetProcessHeap(), 0,
532 max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))))
534 memcpy( pInfo, bmi, size );
535 pInfo->bmiHeader.biHeight /= 2;
537 /* Create the XOR bitmap */
539 if (DoStretch) {
540 if(bIcon)
542 hXorBits = CreateCompatibleBitmap(screen_dc, width, height);
544 else
546 hXorBits = CreateBitmap(width, height, 1, 1, NULL);
548 if(hXorBits)
550 HBITMAP hOld;
551 BOOL res = FALSE;
553 if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
554 if (hdcMem) {
555 hOld = SelectObject(hdcMem, hXorBits);
556 res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
557 bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2,
558 (char*)bmi + size, pInfo, DIB_RGB_COLORS, SRCCOPY);
559 SelectObject(hdcMem, hOld);
561 if (!res) { DeleteObject(hXorBits); hXorBits = 0; }
563 } else hXorBits = CreateDIBitmap( screen_dc, &pInfo->bmiHeader,
564 CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS );
565 if( hXorBits )
567 char* xbits = (char *)bmi + size +
568 DIB_GetDIBImageBytes(bmi->bmiHeader.biWidth,
569 bmi->bmiHeader.biHeight,
570 bmi->bmiHeader.biBitCount) / 2;
572 pInfo->bmiHeader.biBitCount = 1;
573 if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
575 RGBQUAD *rgb = pInfo->bmiColors;
577 pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
578 rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
579 rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
580 rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
582 else
584 RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
586 rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
587 rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
590 /* Create the AND bitmap */
592 if (DoStretch) {
593 if ((hAndBits = CreateBitmap(width, height, 1, 1, NULL))) {
594 HBITMAP hOld;
595 BOOL res = FALSE;
597 if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
598 if (hdcMem) {
599 hOld = SelectObject(hdcMem, hAndBits);
600 res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
601 pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight,
602 xbits, pInfo, DIB_RGB_COLORS, SRCCOPY);
603 SelectObject(hdcMem, hOld);
605 if (!res) { DeleteObject(hAndBits); hAndBits = 0; }
607 } else hAndBits = CreateDIBitmap( screen_dc, &pInfo->bmiHeader,
608 CBM_INIT, xbits, pInfo, DIB_RGB_COLORS );
610 if( !hAndBits ) DeleteObject( hXorBits );
612 HeapFree( GetProcessHeap(), 0, pInfo );
616 if( !hXorBits || !hAndBits )
618 WARN_(cursor)("\tunable to create an icon bitmap.\n");
619 return 0;
622 /* Now create the CURSORICONINFO structure */
623 GetObjectA( hXorBits, sizeof(bmpXor), &bmpXor );
624 GetObjectA( hAndBits, sizeof(bmpAnd), &bmpAnd );
625 sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
626 sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
628 if (hObj) hObj = GlobalReAlloc16( hObj,
629 sizeof(CURSORICONINFO) + sizeXor + sizeAnd, GMEM_MOVEABLE );
630 if (!hObj) hObj = GlobalAlloc16( GMEM_MOVEABLE,
631 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
632 if (hObj)
634 CURSORICONINFO *info;
636 /* Make it owned by the module */
637 if (hInstance) hInstance = GetExePtr(hInstance);
638 FarSetOwner16( hObj, hInstance );
640 info = (CURSORICONINFO *)GlobalLock16( hObj );
641 info->ptHotSpot.x = hotspot.x;
642 info->ptHotSpot.y = hotspot.y;
643 info->nWidth = bmpXor.bmWidth;
644 info->nHeight = bmpXor.bmHeight;
645 info->nWidthBytes = bmpXor.bmWidthBytes;
646 info->bPlanes = bmpXor.bmPlanes;
647 info->bBitsPerPixel = bmpXor.bmBitsPixel;
649 /* Transfer the bitmap bits to the CURSORICONINFO structure */
651 GetBitmapBits( hAndBits, sizeAnd, (char *)(info + 1) );
652 GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
653 GlobalUnlock16( hObj );
656 DeleteObject( hAndBits );
657 DeleteObject( hXorBits );
658 return hObj;
662 /**********************************************************************
663 * CreateIconFromResourceEx (USER.450)
665 * FIXME: not sure about exact parameter types
667 HICON16 WINAPI CreateIconFromResourceEx16( LPBYTE bits, UINT16 cbSize, BOOL16 bIcon,
668 DWORD dwVersion, INT16 width, INT16 height, UINT16 cFlag )
670 return CreateIconFromResourceEx(bits, cbSize, bIcon, dwVersion,
671 width, height, cFlag);
675 /**********************************************************************
676 * CreateIconFromResource (USER32.@)
678 HICON WINAPI CreateIconFromResource( LPBYTE bits, UINT cbSize,
679 BOOL bIcon, DWORD dwVersion)
681 return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
685 /**********************************************************************
686 * CreateIconFromResourceEx (USER32.@)
688 HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
689 BOOL bIcon, DWORD dwVersion,
690 INT width, INT height,
691 UINT cFlag )
693 return CURSORICON_CreateFromResource( 0, 0, bits, cbSize, bIcon, dwVersion,
694 width, height, cFlag );
697 /**********************************************************************
698 * CURSORICON_Load
700 * Load a cursor or icon from resource or file.
702 HGLOBAL CURSORICON_Load( HINSTANCE hInstance, LPCWSTR name,
703 INT width, INT height, INT colors,
704 BOOL fCursor, UINT loadflags )
706 HANDLE handle = 0, h = 0;
707 HANDLE hRsrc;
708 CURSORICONDIR *dir;
709 CURSORICONDIRENTRY *dirEntry;
710 LPBYTE bits;
712 if ( loadflags & LR_LOADFROMFILE ) /* Load from file */
714 LPBYTE *ptr;
715 if (!CURSORICON_SimulateLoadingFromResourceW((LPWSTR)name, fCursor, &dir, &ptr))
716 return 0;
717 if (fCursor)
718 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(dir, width, height, 1);
719 else
720 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(dir, width, height, colors);
721 bits = ptr[dirEntry->wResId-1];
722 h = CURSORICON_CreateFromResource( 0, 0, bits, dirEntry->dwBytesInRes,
723 !fCursor, 0x00030000, width, height, loadflags);
724 HeapFree( GetProcessHeap(), 0, dir );
725 HeapFree( GetProcessHeap(), 0, ptr );
727 else /* Load from resource */
729 HANDLE hGroupRsrc;
730 WORD wResId;
731 DWORD dwBytesInRes;
733 if (!hInstance) /* Load OEM cursor/icon */
735 if (!(hInstance = GetModuleHandleA( "user32.dll" ))) return 0;
738 /* Normalize hInstance (must be uniquely represented for icon cache) */
740 if ( HIWORD( hInstance ) )
741 hInstance = MapHModuleLS( hInstance );
742 else
743 hInstance = GetExePtr( hInstance );
745 /* Get directory resource ID */
747 if (!(hRsrc = FindResourceW( hInstance, name,
748 fCursor ? RT_GROUP_CURSORW : RT_GROUP_ICONW )))
749 return 0;
750 hGroupRsrc = hRsrc;
752 /* Find the best entry in the directory */
754 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
755 if (!(dir = (CURSORICONDIR*)LockResource( handle ))) return 0;
756 if (fCursor)
757 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor( dir,
758 width, height, 1);
759 else
760 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon( dir,
761 width, height, colors );
762 if (!dirEntry) return 0;
763 wResId = dirEntry->wResId;
764 dwBytesInRes = dirEntry->dwBytesInRes;
765 FreeResource( handle );
767 /* Load the resource */
769 if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
770 fCursor ? RT_CURSORW : RT_ICONW ))) return 0;
772 /* If shared icon, check whether it was already loaded */
773 if ( (loadflags & LR_SHARED)
774 && (h = CURSORICON_FindSharedIcon( hInstance, hRsrc ) ) != 0 )
775 return h;
777 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
778 bits = (LPBYTE)LockResource( handle );
779 h = CURSORICON_CreateFromResource( 0, 0, bits, dwBytesInRes,
780 !fCursor, 0x00030000, width, height, loadflags);
781 FreeResource( handle );
783 /* If shared icon, add to icon cache */
785 if ( h && (loadflags & LR_SHARED) )
786 CURSORICON_AddSharedIcon( hInstance, hRsrc, hGroupRsrc, h );
789 return h;
792 /***********************************************************************
793 * CURSORICON_Copy
795 * Make a copy of a cursor or icon.
797 static HGLOBAL16 CURSORICON_Copy( HINSTANCE16 hInstance, HGLOBAL16 handle )
799 char *ptrOld, *ptrNew;
800 int size;
801 HGLOBAL16 hNew;
803 if (!(ptrOld = (char *)GlobalLock16( handle ))) return 0;
804 if (hInstance && !(hInstance = GetExePtr( hInstance ))) return 0;
805 size = GlobalSize16( handle );
806 hNew = GlobalAlloc16( GMEM_MOVEABLE, size );
807 FarSetOwner16( hNew, hInstance );
808 ptrNew = (char *)GlobalLock16( hNew );
809 memcpy( ptrNew, ptrOld, size );
810 GlobalUnlock16( handle );
811 GlobalUnlock16( hNew );
812 return hNew;
815 /*************************************************************************
816 * CURSORICON_ExtCopy
818 * Copies an Image from the Cache if LR_COPYFROMRESOURCE is specified
820 * PARAMS
821 * Handle [I] handle to an Image
822 * nType [I] Type of Handle (IMAGE_CURSOR | IMAGE_ICON)
823 * iDesiredCX [I] The Desired width of the Image
824 * iDesiredCY [I] The desired height of the Image
825 * nFlags [I] The flags from CopyImage
827 * RETURNS
828 * Success: The new handle of the Image
830 * NOTES
831 * LR_COPYDELETEORG and LR_MONOCHROME are currently not implemented.
832 * LR_MONOCHROME should be implemented by CURSORICON_CreateFromResource.
833 * LR_COPYFROMRESOURCE will only work if the Image is in the Cache.
838 HGLOBAL CURSORICON_ExtCopy(HGLOBAL Handle, UINT nType,
839 INT iDesiredCX, INT iDesiredCY,
840 UINT nFlags)
842 HGLOBAL16 hNew=0;
844 TRACE_(icon)("Handle %u, uType %u, iDesiredCX %i, iDesiredCY %i, nFlags %u\n",
845 Handle, nType, iDesiredCX, iDesiredCY, nFlags);
847 if(Handle == 0)
849 return 0;
852 /* Best Fit or Monochrome */
853 if( (nFlags & LR_COPYFROMRESOURCE
854 && (iDesiredCX > 0 || iDesiredCY > 0))
855 || nFlags & LR_MONOCHROME)
857 ICONCACHE* pIconCache = CURSORICON_FindCache(Handle);
859 /* Not Found in Cache, then do a straight copy
861 if(pIconCache == NULL)
863 hNew = CURSORICON_Copy(0, Handle);
864 if(nFlags & LR_COPYFROMRESOURCE)
866 TRACE_(icon)("LR_COPYFROMRESOURCE: Failed to load from cache\n");
869 else
871 int iTargetCY = iDesiredCY, iTargetCX = iDesiredCX;
872 LPBYTE pBits;
873 HANDLE hMem;
874 HRSRC hRsrc;
875 DWORD dwBytesInRes;
876 WORD wResId;
877 CURSORICONDIR *pDir;
878 CURSORICONDIRENTRY *pDirEntry;
879 BOOL bIsIcon = (nType == IMAGE_ICON);
881 /* Completing iDesiredCX CY for Monochrome Bitmaps if needed
883 if(((nFlags & LR_MONOCHROME) && !(nFlags & LR_COPYFROMRESOURCE))
884 || (iDesiredCX == 0 && iDesiredCY == 0))
886 iDesiredCY = GetSystemMetrics(bIsIcon ?
887 SM_CYICON : SM_CYCURSOR);
888 iDesiredCX = GetSystemMetrics(bIsIcon ?
889 SM_CXICON : SM_CXCURSOR);
892 /* Retrieve the CURSORICONDIRENTRY
894 if (!(hMem = LoadResource( pIconCache->hModule ,
895 pIconCache->hGroupRsrc)))
897 return 0;
899 if (!(pDir = (CURSORICONDIR*)LockResource( hMem )))
901 return 0;
904 /* Find Best Fit
906 if(bIsIcon)
908 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(
909 pDir, iDesiredCX, iDesiredCY, 256);
911 else
913 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(
914 pDir, iDesiredCX, iDesiredCY, 1);
917 wResId = pDirEntry->wResId;
918 dwBytesInRes = pDirEntry->dwBytesInRes;
919 FreeResource(hMem);
921 TRACE_(icon)("ResID %u, BytesInRes %lu, Width %d, Height %d DX %d, DY %d\n",
922 wResId, dwBytesInRes, pDirEntry->ResInfo.icon.bWidth,
923 pDirEntry->ResInfo.icon.bHeight, iDesiredCX, iDesiredCY);
925 /* Get the Best Fit
927 if (!(hRsrc = FindResourceW(pIconCache->hModule ,
928 MAKEINTRESOURCEW(wResId), bIsIcon ? RT_ICONW : RT_CURSORW)))
930 return 0;
932 if (!(hMem = LoadResource( pIconCache->hModule , hRsrc )))
934 return 0;
937 pBits = (LPBYTE)LockResource( hMem );
939 if(nFlags & LR_DEFAULTSIZE)
941 iTargetCY = GetSystemMetrics(SM_CYICON);
942 iTargetCX = GetSystemMetrics(SM_CXICON);
945 /* Create a New Icon with the proper dimension
947 hNew = CURSORICON_CreateFromResource( 0, 0, pBits, dwBytesInRes,
948 bIsIcon, 0x00030000, iTargetCX, iTargetCY, nFlags);
949 FreeResource(hMem);
952 else hNew = CURSORICON_Copy(0, Handle);
953 return hNew;
957 /***********************************************************************
958 * LoadCursor (USER.173)
960 HCURSOR16 WINAPI LoadCursor16( HINSTANCE16 hInstance, LPCSTR name )
962 return LoadCursorA( hInstance, name );
966 /***********************************************************************
967 * LoadIcon (USER.174)
969 HICON16 WINAPI LoadIcon16( HINSTANCE16 hInstance, LPCSTR name )
971 return LoadIconA( hInstance, name );
975 /***********************************************************************
976 * CreateCursor (USER.406)
978 HCURSOR16 WINAPI CreateCursor16( HINSTANCE16 hInstance,
979 INT16 xHotSpot, INT16 yHotSpot,
980 INT16 nWidth, INT16 nHeight,
981 LPCVOID lpANDbits, LPCVOID lpXORbits )
983 CURSORICONINFO info;
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;
993 info.bPlanes = 1;
994 info.bBitsPerPixel = 1;
996 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1000 /***********************************************************************
1001 * CreateCursor (USER32.@)
1003 HCURSOR WINAPI CreateCursor( HINSTANCE hInstance,
1004 INT xHotSpot, INT yHotSpot,
1005 INT nWidth, INT nHeight,
1006 LPCVOID lpANDbits, LPCVOID lpXORbits )
1008 CURSORICONINFO info;
1010 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1011 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1013 info.ptHotSpot.x = xHotSpot;
1014 info.ptHotSpot.y = yHotSpot;
1015 info.nWidth = nWidth;
1016 info.nHeight = nHeight;
1017 info.nWidthBytes = 0;
1018 info.bPlanes = 1;
1019 info.bBitsPerPixel = 1;
1021 return CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
1025 /***********************************************************************
1026 * CreateIcon (USER.407)
1028 HICON16 WINAPI CreateIcon16( HINSTANCE16 hInstance, INT16 nWidth,
1029 INT16 nHeight, BYTE bPlanes, BYTE bBitsPixel,
1030 LPCVOID lpANDbits, LPCVOID lpXORbits )
1032 CURSORICONINFO info;
1034 TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1035 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1037 info.ptHotSpot.x = ICON_HOTSPOT;
1038 info.ptHotSpot.y = ICON_HOTSPOT;
1039 info.nWidth = nWidth;
1040 info.nHeight = nHeight;
1041 info.nWidthBytes = 0;
1042 info.bPlanes = bPlanes;
1043 info.bBitsPerPixel = bBitsPixel;
1045 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1049 /***********************************************************************
1050 * CreateIcon (USER32.@)
1052 * Creates an icon based on the specified bitmaps. The bitmaps must be
1053 * provided in a device dependent format and will be resized to
1054 * (SM_CXICON,SM_CYICON) and depth converted to match the screen's color
1055 * depth. The provided bitmaps must be top-down bitmaps.
1056 * Although Windows does not support 15bpp(*) this API must support it
1057 * for Winelib applications.
1059 * (*) Windows does not support 15bpp but it supports the 555 RGB 16bpp
1060 * format!
1062 * BUGS
1064 * - The provided bitmaps are not resized!
1065 * - The documentation says the lpXORbits bitmap must be in a device
1066 * dependent format. But we must still resize it and perform depth
1067 * conversions if necessary.
1068 * - I'm a bit unsure about the how the 'device dependent format' thing works.
1069 * I did some tests on windows and found that if you provide a 16bpp bitmap
1070 * in lpXORbits, then its format but be 565 RGB if the screen's bit depth
1071 * is 16bpp but it must be 555 RGB if the screen's bit depth is anything
1072 * else. I don't know if this is part of the GDI specs or if this is a
1073 * quirk of the graphics card driver.
1074 * - You may think that we check whether the bit depths match or not
1075 * as an optimization. But the truth is that the conversion using
1076 * CreateDIBitmap does not work for some bit depth (e.g. 8bpp) and I have
1077 * no idea why.
1078 * - I'm pretty sure that all the things we do in CreateIcon should
1079 * also be done in CreateIconIndirect...
1081 HICON WINAPI CreateIcon(
1082 HINSTANCE hInstance, /* [in] the application's hInstance, currently unused */
1083 INT nWidth, /* [in] the width of the provided bitmaps */
1084 INT nHeight, /* [in] the height of the provided bitmaps */
1085 BYTE bPlanes, /* [in] the number of planes in the provided bitmaps */
1086 BYTE bBitsPixel, /* [in] the number of bits per pixel of the lpXORbits bitmap */
1087 LPCVOID lpANDbits, /* [in] a monochrome bitmap representing the icon's mask */
1088 LPCVOID lpXORbits) /* [in] the icon's 'color' bitmap */
1090 HICON hIcon;
1091 HDC hdc;
1093 TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1094 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1096 hdc=GetDC(0);
1097 if (!hdc)
1098 return 0;
1100 if (GetDeviceCaps(hdc,BITSPIXEL)==bBitsPixel) {
1101 CURSORICONINFO info;
1103 info.ptHotSpot.x = ICON_HOTSPOT;
1104 info.ptHotSpot.y = ICON_HOTSPOT;
1105 info.nWidth = nWidth;
1106 info.nHeight = nHeight;
1107 info.nWidthBytes = 0;
1108 info.bPlanes = bPlanes;
1109 info.bBitsPerPixel = bBitsPixel;
1111 hIcon=CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
1112 } else {
1113 ICONINFO iinfo;
1114 BITMAPINFO bmi;
1116 iinfo.fIcon=TRUE;
1117 iinfo.xHotspot=ICON_HOTSPOT;
1118 iinfo.yHotspot=ICON_HOTSPOT;
1119 iinfo.hbmMask=CreateBitmap(nWidth,nHeight,1,1,lpANDbits);
1121 bmi.bmiHeader.biSize=sizeof(bmi.bmiHeader);
1122 bmi.bmiHeader.biWidth=nWidth;
1123 bmi.bmiHeader.biHeight=-nHeight;
1124 bmi.bmiHeader.biPlanes=bPlanes;
1125 bmi.bmiHeader.biBitCount=bBitsPixel;
1126 bmi.bmiHeader.biCompression=BI_RGB;
1127 bmi.bmiHeader.biSizeImage=0;
1128 bmi.bmiHeader.biXPelsPerMeter=0;
1129 bmi.bmiHeader.biYPelsPerMeter=0;
1130 bmi.bmiHeader.biClrUsed=0;
1131 bmi.bmiHeader.biClrImportant=0;
1133 iinfo.hbmColor = CreateDIBitmap( hdc, &bmi.bmiHeader,
1134 CBM_INIT, lpXORbits,
1135 &bmi, DIB_RGB_COLORS );
1137 hIcon=CreateIconIndirect(&iinfo);
1138 DeleteObject(iinfo.hbmMask);
1139 DeleteObject(iinfo.hbmColor);
1141 ReleaseDC(0,hdc);
1142 return hIcon;
1146 /***********************************************************************
1147 * CreateCursorIconIndirect (USER.408)
1149 HGLOBAL16 WINAPI CreateCursorIconIndirect16( HINSTANCE16 hInstance,
1150 CURSORICONINFO *info,
1151 LPCVOID lpANDbits,
1152 LPCVOID lpXORbits )
1154 HGLOBAL16 handle;
1155 char *ptr;
1156 int sizeAnd, sizeXor;
1158 hInstance = GetExePtr( hInstance ); /* Make it a module handle */
1159 if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
1160 info->nWidthBytes = BITMAP_GetWidthBytes(info->nWidth,info->bBitsPerPixel);
1161 sizeXor = info->nHeight * info->nWidthBytes;
1162 sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
1163 if (!(handle = GlobalAlloc16( GMEM_MOVEABLE,
1164 sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
1165 return 0;
1166 FarSetOwner16( handle, hInstance );
1167 ptr = (char *)GlobalLock16( handle );
1168 memcpy( ptr, info, sizeof(*info) );
1169 memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
1170 memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
1171 GlobalUnlock16( handle );
1172 return handle;
1176 /***********************************************************************
1177 * CopyIcon (USER.368)
1179 HICON16 WINAPI CopyIcon16( HINSTANCE16 hInstance, HICON16 hIcon )
1181 TRACE_(icon)("%04x %04x\n", hInstance, hIcon );
1182 return CURSORICON_Copy( hInstance, hIcon );
1186 /***********************************************************************
1187 * CopyIcon (USER32.@)
1189 HICON WINAPI CopyIcon( HICON hIcon )
1191 TRACE_(icon)("%04x\n", hIcon );
1192 return CURSORICON_Copy( 0, hIcon );
1196 /***********************************************************************
1197 * CopyCursor (USER.369)
1199 HCURSOR16 WINAPI CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
1201 TRACE_(cursor)("%04x %04x\n", hInstance, hCursor );
1202 return CURSORICON_Copy( hInstance, hCursor );
1205 /**********************************************************************
1206 * DestroyIcon32 (USER.610)
1207 * DestroyIcon32 (USER32.@)
1209 * This routine is actually exported from Win95 USER under the name
1210 * DestroyIcon32 ... The behaviour implemented here should mimic
1211 * the Win95 one exactly, especially the return values, which
1212 * depend on the setting of various flags.
1214 WORD WINAPI DestroyIcon32( HGLOBAL16 handle, UINT16 flags )
1216 WORD retv;
1218 TRACE_(icon)("(%04x, %04x)\n", handle, flags );
1220 /* Check whether destroying active cursor */
1222 if ( QUEUE_Current()->cursor == handle )
1224 WARN_(cursor)("Destroying active cursor!\n" );
1225 SetCursor( 0 );
1228 /* Try shared cursor/icon first */
1230 if ( !(flags & CID_NONSHARED) )
1232 INT count = CURSORICON_DelSharedIcon( handle );
1234 if ( count != -1 )
1235 return (flags & CID_WIN32)? TRUE : (count == 0);
1237 /* FIXME: OEM cursors/icons should be recognized */
1240 /* Now assume non-shared cursor/icon */
1242 retv = GlobalFree16( handle );
1243 return (flags & CID_RESOURCE)? retv : TRUE;
1246 /***********************************************************************
1247 * DestroyIcon (USER.457)
1249 BOOL16 WINAPI DestroyIcon16( HICON16 hIcon )
1251 return DestroyIcon32( hIcon, 0 );
1254 /***********************************************************************
1255 * DestroyIcon (USER32.@)
1257 BOOL WINAPI DestroyIcon( HICON hIcon )
1259 return DestroyIcon32( hIcon, CID_WIN32 );
1262 /***********************************************************************
1263 * DestroyCursor (USER.458)
1265 BOOL16 WINAPI DestroyCursor16( HCURSOR16 hCursor )
1267 return DestroyIcon32( hCursor, 0 );
1270 /***********************************************************************
1271 * DestroyCursor (USER32.@)
1273 BOOL WINAPI DestroyCursor( HCURSOR hCursor )
1275 return DestroyIcon32( hCursor, CID_WIN32 );
1279 /***********************************************************************
1280 * DrawIcon (USER.84)
1282 BOOL16 WINAPI DrawIcon16( HDC16 hdc, INT16 x, INT16 y, HICON16 hIcon )
1284 return DrawIcon( hdc, x, y, hIcon );
1288 /***********************************************************************
1289 * DrawIcon (USER32.@)
1291 BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
1293 CURSORICONINFO *ptr;
1294 HDC hMemDC;
1295 HBITMAP hXorBits, hAndBits;
1296 COLORREF oldFg, oldBg;
1298 if (!(ptr = (CURSORICONINFO *)GlobalLock16( hIcon ))) return FALSE;
1299 if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
1300 hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1,
1301 (char *)(ptr+1) );
1302 hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
1303 ptr->bBitsPerPixel, (char *)(ptr + 1)
1304 + ptr->nHeight * BITMAP_GetWidthBytes(ptr->nWidth,1) );
1305 oldFg = SetTextColor( hdc, RGB(0,0,0) );
1306 oldBg = SetBkColor( hdc, RGB(255,255,255) );
1308 if (hXorBits && hAndBits)
1310 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1311 BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
1312 SelectObject( hMemDC, hXorBits );
1313 BitBlt(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
1314 SelectObject( hMemDC, hBitTemp );
1316 DeleteDC( hMemDC );
1317 if (hXorBits) DeleteObject( hXorBits );
1318 if (hAndBits) DeleteObject( hAndBits );
1319 GlobalUnlock16( hIcon );
1320 SetTextColor( hdc, oldFg );
1321 SetBkColor( hdc, oldBg );
1322 return TRUE;
1326 /***********************************************************************
1327 * IconSize (USER.86)
1329 * See "Undocumented Windows". Used by W2.0 paint.exe.
1331 DWORD WINAPI IconSize16( void )
1333 return MAKELONG(GetSystemMetrics(SM_CYICON), GetSystemMetrics(SM_CXICON));
1337 /***********************************************************************
1338 * DumpIcon (USER.459)
1340 DWORD WINAPI DumpIcon16( SEGPTR pInfo, WORD *lpLen,
1341 SEGPTR *lpXorBits, SEGPTR *lpAndBits )
1343 CURSORICONINFO *info = MapSL( pInfo );
1344 int sizeAnd, sizeXor;
1346 if (!info) return 0;
1347 sizeXor = info->nHeight * info->nWidthBytes;
1348 sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
1349 if (lpAndBits) *lpAndBits = pInfo + sizeof(CURSORICONINFO);
1350 if (lpXorBits) *lpXorBits = pInfo + sizeof(CURSORICONINFO) + sizeAnd;
1351 if (lpLen) *lpLen = sizeof(CURSORICONINFO) + sizeAnd + sizeXor;
1352 return MAKELONG( sizeXor, sizeXor );
1356 /***********************************************************************
1357 * SetCursor (USER.69)
1359 HCURSOR16 WINAPI SetCursor16( HCURSOR16 hCursor )
1361 return (HCURSOR16)SetCursor( hCursor );
1365 /***********************************************************************
1366 * SetCursor (USER32.@)
1367 * RETURNS:
1368 * A handle to the previous cursor shape.
1370 HCURSOR WINAPI SetCursor( HCURSOR hCursor /* [in] Handle of cursor to show */ )
1372 MESSAGEQUEUE *queue = QUEUE_Current();
1373 HCURSOR hOldCursor;
1375 if (hCursor == queue->cursor) return hCursor; /* No change */
1376 TRACE_(cursor)("%04x\n", hCursor );
1377 hOldCursor = queue->cursor;
1378 queue->cursor = hCursor;
1379 /* Change the cursor shape only if it is visible */
1380 if (queue->cursor_count >= 0)
1382 USER_Driver.pSetCursor( (CURSORICONINFO*)GlobalLock16( hCursor ) );
1383 GlobalUnlock16( hCursor );
1385 return hOldCursor;
1389 /***********************************************************************
1390 * ShowCursor (USER.71)
1392 INT16 WINAPI ShowCursor16( BOOL16 bShow )
1394 return ShowCursor( bShow );
1398 /***********************************************************************
1399 * ShowCursor (USER32.@)
1401 INT WINAPI ShowCursor( BOOL bShow )
1403 MESSAGEQUEUE *queue = QUEUE_Current();
1405 TRACE_(cursor)("%d, count=%d\n", bShow, queue->cursor_count );
1407 if (bShow)
1409 if (++queue->cursor_count == 0) /* Show it */
1411 USER_Driver.pSetCursor( (CURSORICONINFO*)GlobalLock16( queue->cursor ) );
1412 GlobalUnlock16( queue->cursor );
1415 else
1417 if (--queue->cursor_count == -1) /* Hide it */
1418 USER_Driver.pSetCursor( NULL );
1420 return queue->cursor_count;
1424 /***********************************************************************
1425 * GetCursor (USER.247)
1427 HCURSOR16 WINAPI GetCursor16(void)
1429 return GetCursor();
1433 /***********************************************************************
1434 * GetCursor (USER32.@)
1436 HCURSOR WINAPI GetCursor(void)
1438 return QUEUE_Current()->cursor;
1442 /***********************************************************************
1443 * ClipCursor (USER.16)
1445 BOOL16 WINAPI ClipCursor16( const RECT16 *rect )
1447 if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1448 else CONV_RECT16TO32( rect, &CURSOR_ClipRect );
1449 return TRUE;
1453 /***********************************************************************
1454 * ClipCursor (USER32.@)
1456 BOOL WINAPI ClipCursor( const RECT *rect )
1458 if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1459 else CopyRect( &CURSOR_ClipRect, rect );
1460 return TRUE;
1464 /***********************************************************************
1465 * GetClipCursor (USER.309)
1467 void WINAPI GetClipCursor16( RECT16 *rect )
1469 if (rect) CONV_RECT32TO16( &CURSOR_ClipRect, rect );
1473 /***********************************************************************
1474 * GetClipCursor (USER32.@)
1476 BOOL WINAPI GetClipCursor( RECT *rect )
1478 if (rect)
1480 CopyRect( rect, &CURSOR_ClipRect );
1481 return TRUE;
1483 return FALSE;
1486 /**********************************************************************
1487 * LookupIconIdFromDirectoryEx (USER.364)
1489 * FIXME: exact parameter sizes
1491 INT16 WINAPI LookupIconIdFromDirectoryEx16( LPBYTE xdir, BOOL16 bIcon,
1492 INT16 width, INT16 height, UINT16 cFlag )
1494 CURSORICONDIR *dir = (CURSORICONDIR*)xdir;
1495 UINT16 retVal = 0;
1496 if( dir && !dir->idReserved && (dir->idType & 3) )
1498 CURSORICONDIRENTRY* entry;
1499 HDC hdc;
1500 UINT palEnts;
1501 int colors;
1502 hdc = GetDC(0);
1503 palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
1504 if (palEnts == 0)
1505 palEnts = 256;
1506 colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
1508 ReleaseDC(0, hdc);
1510 if( bIcon )
1511 entry = CURSORICON_FindBestIcon( dir, width, height, colors );
1512 else
1513 entry = CURSORICON_FindBestCursor( dir, width, height, 1);
1515 if( entry ) retVal = entry->wResId;
1517 else WARN_(cursor)("invalid resource directory\n");
1518 return retVal;
1521 /**********************************************************************
1522 * LookupIconIdFromDirectoryEx (USER32.@)
1524 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE dir, BOOL bIcon,
1525 INT width, INT height, UINT cFlag )
1527 return LookupIconIdFromDirectoryEx16( dir, bIcon, width, height, cFlag );
1530 /**********************************************************************
1531 * LookupIconIdFromDirectory (USER.?)
1533 INT16 WINAPI LookupIconIdFromDirectory16( LPBYTE dir, BOOL16 bIcon )
1535 return LookupIconIdFromDirectoryEx16( dir, bIcon,
1536 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1537 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1540 /**********************************************************************
1541 * LookupIconIdFromDirectory (USER32.@)
1543 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1545 return LookupIconIdFromDirectoryEx( dir, bIcon,
1546 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1547 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1550 /**********************************************************************
1551 * GetIconID (USER.455)
1553 WORD WINAPI GetIconID16( HGLOBAL16 hResource, DWORD resType )
1555 LPBYTE lpDir = (LPBYTE)GlobalLock16(hResource);
1557 TRACE_(cursor)("hRes=%04x, entries=%i\n",
1558 hResource, lpDir ? ((CURSORICONDIR*)lpDir)->idCount : 0);
1560 switch(resType)
1562 case RT_CURSOR16:
1563 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, FALSE,
1564 GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1565 case RT_ICON16:
1566 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, TRUE,
1567 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0 );
1568 default:
1569 WARN_(cursor)("invalid res type %ld\n", resType );
1571 return 0;
1574 /**********************************************************************
1575 * LoadCursorIconHandler (USER.336)
1577 * Supposed to load resources of Windows 2.x applications.
1579 HGLOBAL16 WINAPI LoadCursorIconHandler16( HGLOBAL16 hResource, HMODULE16 hModule, HRSRC16 hRsrc )
1581 FIXME_(cursor)("(%04x,%04x,%04x): old 2.x resources are not supported!\n",
1582 hResource, hModule, hRsrc);
1583 return (HGLOBAL16)0;
1586 /**********************************************************************
1587 * LoadDIBIconHandler (USER.357)
1589 * RT_ICON resource loader, installed by USER_SignalProc when module
1590 * is initialized.
1592 HGLOBAL16 WINAPI LoadDIBIconHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1594 /* If hResource is zero we must allocate a new memory block, if it's
1595 * non-zero but GlobalLock() returns NULL then it was discarded and
1596 * we have to recommit some memory, otherwise we just need to check
1597 * the block size. See LoadProc() in 16-bit SDK for more.
1600 hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1601 if( hMemObj )
1603 LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1604 hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1605 SizeofResource16(hModule, hRsrc), TRUE, 0x00030000,
1606 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR );
1608 return hMemObj;
1611 /**********************************************************************
1612 * LoadDIBCursorHandler (USER.356)
1614 * RT_CURSOR resource loader. Same as above.
1616 HGLOBAL16 WINAPI LoadDIBCursorHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1618 hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1619 if( hMemObj )
1621 LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1622 hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1623 SizeofResource16(hModule, hRsrc), FALSE, 0x00030000,
1624 GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1626 return hMemObj;
1629 /**********************************************************************
1630 * LoadIconHandler (USER.456)
1632 HICON16 WINAPI LoadIconHandler16( HGLOBAL16 hResource, BOOL16 bNew )
1634 LPBYTE bits = (LPBYTE)LockResource16( hResource );
1636 TRACE_(cursor)("hRes=%04x\n",hResource);
1638 return CURSORICON_CreateFromResource( 0, 0, bits, 0, TRUE,
1639 bNew ? 0x00030000 : 0x00020000, 0, 0, LR_DEFAULTCOLOR );
1642 /***********************************************************************
1643 * LoadCursorW (USER32.@)
1645 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
1647 return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0,
1648 LR_SHARED | LR_DEFAULTSIZE );
1651 /***********************************************************************
1652 * LoadCursorA (USER32.@)
1654 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
1656 return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0,
1657 LR_SHARED | LR_DEFAULTSIZE );
1660 /***********************************************************************
1661 * LoadCursorFromFileW (USER32.@)
1663 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
1665 return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0,
1666 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1669 /***********************************************************************
1670 * LoadCursorFromFileA (USER32.@)
1672 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
1674 return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0,
1675 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1678 /***********************************************************************
1679 * LoadIconW (USER32.@)
1681 HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
1683 return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0,
1684 LR_SHARED | LR_DEFAULTSIZE );
1687 /***********************************************************************
1688 * LoadIconA (USER32.@)
1690 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
1692 return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0,
1693 LR_SHARED | LR_DEFAULTSIZE );
1696 /**********************************************************************
1697 * GetIconInfo (USER.395)
1699 BOOL16 WINAPI GetIconInfo16(HICON16 hIcon,LPICONINFO16 iconinfo)
1701 ICONINFO ii32;
1702 BOOL16 ret = GetIconInfo((HICON)hIcon, &ii32);
1704 iconinfo->fIcon = ii32.fIcon;
1705 iconinfo->xHotspot = ii32.xHotspot;
1706 iconinfo->yHotspot = ii32.yHotspot;
1707 iconinfo->hbmMask = ii32.hbmMask;
1708 iconinfo->hbmColor = ii32.hbmColor;
1709 return ret;
1712 /**********************************************************************
1713 * GetIconInfo (USER32.@)
1715 BOOL WINAPI GetIconInfo(HICON hIcon,PICONINFO iconinfo) {
1716 CURSORICONINFO *ciconinfo;
1718 ciconinfo = GlobalLock16(hIcon);
1719 if (!ciconinfo)
1720 return FALSE;
1722 if ( (ciconinfo->ptHotSpot.x == ICON_HOTSPOT) &&
1723 (ciconinfo->ptHotSpot.y == ICON_HOTSPOT) )
1725 iconinfo->fIcon = TRUE;
1726 iconinfo->xHotspot = ciconinfo->nWidth / 2;
1727 iconinfo->yHotspot = ciconinfo->nHeight / 2;
1729 else
1731 iconinfo->fIcon = FALSE;
1732 iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
1733 iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
1736 iconinfo->hbmColor = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1737 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
1738 (char *)(ciconinfo + 1)
1739 + ciconinfo->nHeight *
1740 BITMAP_GetWidthBytes (ciconinfo->nWidth,1) );
1741 iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1742 1, 1, (char *)(ciconinfo + 1));
1744 GlobalUnlock16(hIcon);
1746 return TRUE;
1749 /**********************************************************************
1750 * CreateIconIndirect (USER32.@)
1752 HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
1754 BITMAP bmpXor,bmpAnd;
1755 HICON hObj;
1756 int sizeXor,sizeAnd;
1758 GetObjectA( iconinfo->hbmColor, sizeof(bmpXor), &bmpXor );
1759 GetObjectA( iconinfo->hbmMask, sizeof(bmpAnd), &bmpAnd );
1761 sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
1762 sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
1764 hObj = GlobalAlloc16( GMEM_MOVEABLE,
1765 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
1766 if (hObj)
1768 CURSORICONINFO *info;
1770 info = (CURSORICONINFO *)GlobalLock16( hObj );
1772 /* If we are creating an icon, the hotspot is unused */
1773 if (iconinfo->fIcon)
1775 info->ptHotSpot.x = ICON_HOTSPOT;
1776 info->ptHotSpot.y = ICON_HOTSPOT;
1778 else
1780 info->ptHotSpot.x = iconinfo->xHotspot;
1781 info->ptHotSpot.y = iconinfo->yHotspot;
1784 info->nWidth = bmpXor.bmWidth;
1785 info->nHeight = bmpXor.bmHeight;
1786 info->nWidthBytes = bmpXor.bmWidthBytes;
1787 info->bPlanes = bmpXor.bmPlanes;
1788 info->bBitsPerPixel = bmpXor.bmBitsPixel;
1790 /* Transfer the bitmap bits to the CURSORICONINFO structure */
1792 GetBitmapBits( iconinfo->hbmMask ,sizeAnd,(char*)(info + 1) );
1793 GetBitmapBits( iconinfo->hbmColor,sizeXor,(char*)(info + 1) +sizeAnd);
1794 GlobalUnlock16( hObj );
1796 return hObj;
1800 /**********************************************************************
1801 * DrawIconEx (USER.394)
1803 BOOL16 WINAPI DrawIconEx16 (HDC16 hdc, INT16 xLeft, INT16 yTop, HICON16 hIcon,
1804 INT16 cxWidth, INT16 cyWidth, UINT16 istep,
1805 HBRUSH16 hbr, UINT16 flags)
1807 return DrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
1808 istep, hbr, flags);
1812 /******************************************************************************
1813 * DrawIconEx (USER32.@) Draws an icon or cursor on device context
1815 * NOTES
1816 * Why is this using SM_CXICON instead of SM_CXCURSOR?
1818 * PARAMS
1819 * hdc [I] Handle to device context
1820 * x0 [I] X coordinate of upper left corner
1821 * y0 [I] Y coordinate of upper left corner
1822 * hIcon [I] Handle to icon to draw
1823 * cxWidth [I] Width of icon
1824 * cyWidth [I] Height of icon
1825 * istep [I] Index of frame in animated cursor
1826 * hbr [I] Handle to background brush
1827 * flags [I] Icon-drawing flags
1829 * RETURNS
1830 * Success: TRUE
1831 * Failure: FALSE
1833 BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
1834 INT cxWidth, INT cyWidth, UINT istep,
1835 HBRUSH hbr, UINT flags )
1837 CURSORICONINFO *ptr = (CURSORICONINFO *)GlobalLock16 (hIcon);
1838 HDC hDC_off = 0, hMemDC = CreateCompatibleDC (hdc);
1839 BOOL result = FALSE, DoOffscreen;
1840 HBITMAP hB_off = 0, hOld = 0;
1842 if (!ptr) return FALSE;
1843 TRACE_(icon)("(hdc=%x,pos=%d.%d,hicon=%x,extend=%d.%d,istep=%d,br=%x,flags=0x%08x)\n",
1844 hdc,x0,y0,hIcon,cxWidth,cyWidth,istep,hbr,flags
1847 if (istep)
1848 FIXME_(icon)("Ignoring istep=%d\n", istep);
1849 if (flags & DI_COMPAT)
1850 FIXME_(icon)("Ignoring flag DI_COMPAT\n");
1852 if (!flags) {
1853 FIXME_(icon)("no flags set? setting to DI_NORMAL\n");
1854 flags = DI_NORMAL;
1857 /* Calculate the size of the destination image. */
1858 if (cxWidth == 0)
1860 if (flags & DI_DEFAULTSIZE)
1861 cxWidth = GetSystemMetrics (SM_CXICON);
1862 else
1863 cxWidth = ptr->nWidth;
1865 if (cyWidth == 0)
1867 if (flags & DI_DEFAULTSIZE)
1868 cyWidth = GetSystemMetrics (SM_CYICON);
1869 else
1870 cyWidth = ptr->nHeight;
1873 DoOffscreen = (GetObjectType( hbr ) == OBJ_BRUSH);
1875 if (DoOffscreen) {
1876 RECT r;
1878 r.left = 0;
1879 r.top = 0;
1880 r.right = cxWidth;
1881 r.bottom = cxWidth;
1883 hDC_off = CreateCompatibleDC(hdc);
1884 hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth);
1885 if (hDC_off && hB_off) {
1886 hOld = SelectObject(hDC_off, hB_off);
1887 FillRect(hDC_off, &r, hbr);
1891 if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
1893 HBITMAP hXorBits, hAndBits;
1894 COLORREF oldFg, oldBg;
1895 INT nStretchMode;
1897 nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
1899 hXorBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1900 ptr->bPlanes, ptr->bBitsPerPixel,
1901 (char *)(ptr + 1)
1902 + ptr->nHeight *
1903 BITMAP_GetWidthBytes(ptr->nWidth,1) );
1904 hAndBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1905 1, 1, (char *)(ptr+1) );
1906 oldFg = SetTextColor( hdc, RGB(0,0,0) );
1907 oldBg = SetBkColor( hdc, RGB(255,255,255) );
1909 if (hXorBits && hAndBits)
1911 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1912 if (flags & DI_MASK)
1914 if (DoOffscreen)
1915 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1916 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1917 else
1918 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
1919 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1921 SelectObject( hMemDC, hXorBits );
1922 if (flags & DI_IMAGE)
1924 if (DoOffscreen)
1925 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1926 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
1927 else
1928 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
1929 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
1931 SelectObject( hMemDC, hBitTemp );
1932 result = TRUE;
1935 SetTextColor( hdc, oldFg );
1936 SetBkColor( hdc, oldBg );
1937 if (hXorBits) DeleteObject( hXorBits );
1938 if (hAndBits) DeleteObject( hAndBits );
1939 SetStretchBltMode (hdc, nStretchMode);
1940 if (DoOffscreen) {
1941 BitBlt(hdc, x0, y0, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
1942 SelectObject(hDC_off, hOld);
1945 if (hMemDC) DeleteDC( hMemDC );
1946 if (hDC_off) DeleteDC(hDC_off);
1947 if (hB_off) DeleteObject(hB_off);
1948 GlobalUnlock16( hIcon );
1949 return result;
1952 /***********************************************************************
1953 * DIB_FixColorsToLoadflags
1955 * Change color table entries when LR_LOADTRANSPARENT or LR_LOADMAP3DCOLORS
1956 * are in loadflags
1958 static void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags, BYTE pix)
1960 int colors;
1961 COLORREF c_W, c_S, c_F, c_L, c_C;
1962 int incr,i;
1963 RGBQUAD *ptr;
1965 if (bmi->bmiHeader.biBitCount > 8) return;
1966 if (bmi->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)) incr = 4;
1967 else if (bmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) incr = 3;
1968 else {
1969 WARN_(resource)("Wrong bitmap header size!\n");
1970 return;
1972 colors = bmi->bmiHeader.biClrUsed;
1973 if (!colors && (bmi->bmiHeader.biBitCount <= 8))
1974 colors = 1 << bmi->bmiHeader.biBitCount;
1975 c_W = GetSysColor(COLOR_WINDOW);
1976 c_S = GetSysColor(COLOR_3DSHADOW);
1977 c_F = GetSysColor(COLOR_3DFACE);
1978 c_L = GetSysColor(COLOR_3DLIGHT);
1979 if (loadflags & LR_LOADTRANSPARENT) {
1980 switch (bmi->bmiHeader.biBitCount) {
1981 case 1: pix = pix >> 7; break;
1982 case 4: pix = pix >> 4; break;
1983 case 8: break;
1984 default:
1985 WARN_(resource)("(%d): Unsupported depth\n", bmi->bmiHeader.biBitCount);
1986 return;
1988 if (pix >= colors) {
1989 WARN_(resource)("pixel has color index greater than biClrUsed!\n");
1990 return;
1992 if (loadflags & LR_LOADMAP3DCOLORS) c_W = c_F;
1993 ptr = (RGBQUAD*)((char*)bmi->bmiColors+pix*incr);
1994 ptr->rgbBlue = GetBValue(c_W);
1995 ptr->rgbGreen = GetGValue(c_W);
1996 ptr->rgbRed = GetRValue(c_W);
1998 if (loadflags & LR_LOADMAP3DCOLORS)
1999 for (i=0; i<colors; i++) {
2000 ptr = (RGBQUAD*)((char*)bmi->bmiColors+i*incr);
2001 c_C = RGB(ptr->rgbRed, ptr->rgbGreen, ptr->rgbBlue);
2002 if (c_C == RGB(128, 128, 128)) {
2003 ptr->rgbRed = GetRValue(c_S);
2004 ptr->rgbGreen = GetGValue(c_S);
2005 ptr->rgbBlue = GetBValue(c_S);
2006 } else if (c_C == RGB(192, 192, 192)) {
2007 ptr->rgbRed = GetRValue(c_F);
2008 ptr->rgbGreen = GetGValue(c_F);
2009 ptr->rgbBlue = GetBValue(c_F);
2010 } else if (c_C == RGB(223, 223, 223)) {
2011 ptr->rgbRed = GetRValue(c_L);
2012 ptr->rgbGreen = GetGValue(c_L);
2013 ptr->rgbBlue = GetBValue(c_L);
2019 /**********************************************************************
2020 * BITMAP_Load
2022 static HBITMAP BITMAP_Load( HINSTANCE instance,LPCWSTR name, UINT loadflags )
2024 HBITMAP hbitmap = 0;
2025 HRSRC hRsrc;
2026 HGLOBAL handle;
2027 char *ptr = NULL;
2028 BITMAPINFO *info, *fix_info=NULL;
2029 HGLOBAL hFix;
2030 int size;
2032 if (!(loadflags & LR_LOADFROMFILE))
2034 if (!instance)
2036 /* OEM bitmap: try to load the resource from user32.dll */
2037 if (HIWORD(name)) return 0;
2038 if (!(instance = GetModuleHandleA("user32.dll"))) return 0;
2040 if (!(hRsrc = FindResourceW( instance, name, RT_BITMAPW ))) return 0;
2041 if (!(handle = LoadResource( instance, hRsrc ))) return 0;
2043 if ((info = (BITMAPINFO *)LockResource( handle )) == NULL) return 0;
2045 else
2047 if (!(ptr = map_fileW( name ))) return 0;
2048 info = (BITMAPINFO *)(ptr + sizeof(BITMAPFILEHEADER));
2050 size = DIB_BitmapInfoSize(info, DIB_RGB_COLORS);
2051 if ((hFix = GlobalAlloc(0, size))) fix_info=GlobalLock(hFix);
2052 if (fix_info) {
2053 BYTE pix;
2055 memcpy(fix_info, info, size);
2056 pix = *((LPBYTE)info+DIB_BitmapInfoSize(info, DIB_RGB_COLORS));
2057 DIB_FixColorsToLoadflags(fix_info, loadflags, pix);
2058 if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
2059 if (screen_dc)
2061 char *bits = (char *)info + size;
2062 if (loadflags & LR_CREATEDIBSECTION) {
2063 DIBSECTION dib;
2064 hbitmap = CreateDIBSection(screen_dc, fix_info, DIB_RGB_COLORS, NULL, 0, 0);
2065 GetObjectA(hbitmap, sizeof(DIBSECTION), &dib);
2066 SetDIBits(screen_dc, hbitmap, 0, dib.dsBm.bmHeight, bits, info,
2067 DIB_RGB_COLORS);
2069 else {
2070 hbitmap = CreateDIBitmap( screen_dc, &fix_info->bmiHeader, CBM_INIT,
2071 bits, fix_info, DIB_RGB_COLORS );
2074 GlobalUnlock(hFix);
2075 GlobalFree(hFix);
2077 if (loadflags & LR_LOADFROMFILE) UnmapViewOfFile( ptr );
2078 return hbitmap;
2082 /***********************************************************************
2083 * LoadImage (USER.389)
2086 HANDLE16 WINAPI LoadImage16( HINSTANCE16 hinst, LPCSTR name, UINT16 type,
2087 INT16 desiredx, INT16 desiredy, UINT16 loadflags)
2089 return LoadImageA( hinst, name, type, desiredx, desiredy, loadflags );
2092 /**********************************************************************
2093 * LoadImageA (USER32.@)
2095 * FIXME: implementation lacks some features, see LR_ defines in winuser.h
2098 /* filter for page-fault exceptions */
2099 static WINE_EXCEPTION_FILTER(page_fault)
2101 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
2102 return EXCEPTION_EXECUTE_HANDLER;
2103 return EXCEPTION_CONTINUE_SEARCH;
2106 /*********************************************************************/
2108 HANDLE WINAPI LoadImageA( HINSTANCE hinst, LPCSTR name, UINT type,
2109 INT desiredx, INT desiredy, UINT loadflags)
2111 HANDLE res;
2112 LPWSTR u_name;
2114 if (!HIWORD(name))
2115 return LoadImageW(hinst, (LPWSTR)name, type, desiredx, desiredy, loadflags);
2117 __TRY {
2118 DWORD len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
2119 u_name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2120 MultiByteToWideChar( CP_ACP, 0, name, -1, u_name, len );
2122 __EXCEPT(page_fault) {
2123 SetLastError( ERROR_INVALID_PARAMETER );
2124 return 0;
2126 __ENDTRY
2127 res = LoadImageW(hinst, u_name, type, desiredx, desiredy, loadflags);
2128 HeapFree(GetProcessHeap(), 0, u_name);
2129 return res;
2133 /******************************************************************************
2134 * LoadImageW (USER32.@) Loads an icon, cursor, or bitmap
2136 * PARAMS
2137 * hinst [I] Handle of instance that contains image
2138 * name [I] Name of image
2139 * type [I] Type of image
2140 * desiredx [I] Desired width
2141 * desiredy [I] Desired height
2142 * loadflags [I] Load flags
2144 * RETURNS
2145 * Success: Handle to newly loaded image
2146 * Failure: NULL
2148 * FIXME: Implementation lacks some features, see LR_ defines in winuser.h
2150 HANDLE WINAPI LoadImageW( HINSTANCE hinst, LPCWSTR name, UINT type,
2151 INT desiredx, INT desiredy, UINT loadflags )
2153 if (HIWORD(name)) {
2154 TRACE_(resource)("(0x%04x,%p,%d,%d,%d,0x%08x)\n",
2155 hinst,name,type,desiredx,desiredy,loadflags);
2156 } else {
2157 TRACE_(resource)("(0x%04x,%p,%d,%d,%d,0x%08x)\n",
2158 hinst,name,type,desiredx,desiredy,loadflags);
2160 if (loadflags & LR_DEFAULTSIZE) {
2161 if (type == IMAGE_ICON) {
2162 if (!desiredx) desiredx = GetSystemMetrics(SM_CXICON);
2163 if (!desiredy) desiredy = GetSystemMetrics(SM_CYICON);
2164 } else if (type == IMAGE_CURSOR) {
2165 if (!desiredx) desiredx = GetSystemMetrics(SM_CXCURSOR);
2166 if (!desiredy) desiredy = GetSystemMetrics(SM_CYCURSOR);
2169 if (loadflags & LR_LOADFROMFILE) loadflags &= ~LR_SHARED;
2170 switch (type) {
2171 case IMAGE_BITMAP:
2172 return BITMAP_Load( hinst, name, loadflags );
2174 case IMAGE_ICON:
2175 if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
2176 if (screen_dc)
2178 UINT palEnts = GetSystemPaletteEntries(screen_dc, 0, 0, NULL);
2179 if (palEnts == 0) palEnts = 256;
2180 return CURSORICON_Load(hinst, name, desiredx, desiredy,
2181 palEnts, FALSE, loadflags);
2183 break;
2185 case IMAGE_CURSOR:
2186 return CURSORICON_Load(hinst, name, desiredx, desiredy,
2187 1, TRUE, loadflags);
2189 return 0;
2193 /******************************************************************************
2194 * CopyImage (USER.390) Creates new image and copies attributes to it
2197 HICON16 WINAPI CopyImage16( HANDLE16 hnd, UINT16 type, INT16 desiredx,
2198 INT16 desiredy, UINT16 flags )
2200 return (HICON16)CopyImage((HANDLE)hnd, (UINT)type, (INT)desiredx,
2201 (INT)desiredy, (UINT)flags);
2204 /******************************************************************************
2205 * CopyImage (USER32.@) Creates new image and copies attributes to it
2207 * PARAMS
2208 * hnd [I] Handle to image to copy
2209 * type [I] Type of image to copy
2210 * desiredx [I] Desired width of new image
2211 * desiredy [I] Desired height of new image
2212 * flags [I] Copy flags
2214 * RETURNS
2215 * Success: Handle to newly created image
2216 * Failure: NULL
2218 * FIXME: implementation still lacks nearly all features, see LR_*
2219 * defines in winuser.h
2221 HICON WINAPI CopyImage( HANDLE hnd, UINT type, INT desiredx,
2222 INT desiredy, UINT flags )
2224 switch (type)
2226 case IMAGE_BITMAP:
2227 return BITMAP_CopyBitmap(hnd);
2228 case IMAGE_ICON:
2229 return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags);
2230 case IMAGE_CURSOR:
2231 /* Should call CURSORICON_ExtCopy but more testing
2232 * needs to be done before we change this
2234 return CopyCursor(hnd);
2236 return 0;
2240 /******************************************************************************
2241 * LoadBitmapW (USER32.@) Loads bitmap from the executable file
2243 * RETURNS
2244 * Success: Handle to specified bitmap
2245 * Failure: NULL
2247 HBITMAP WINAPI LoadBitmapW(
2248 HINSTANCE instance, /* [in] Handle to application instance */
2249 LPCWSTR name) /* [in] Address of bitmap resource name */
2251 return LoadImageW( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2254 /**********************************************************************
2255 * LoadBitmapA (USER32.@)
2257 HBITMAP WINAPI LoadBitmapA( HINSTANCE instance, LPCSTR name )
2259 return LoadImageA( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2262 /**********************************************************************
2263 * LoadBitmap (USER.175)
2265 HBITMAP16 WINAPI LoadBitmap16( HINSTANCE16 instance, LPCSTR name )
2267 return LoadBitmapA( instance, name );