Replace SELECTOR_AllocBlock and SELECTOR_FreeBlock with standard Win16
[wine/wine-kai.git] / windows / cursoricon.c
blob022b7351ab8c04507b4809cc4b200f9d7aafba4f
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 "palette.h"
55 #include "bitmap.h"
56 #include "cursoricon.h"
57 #include "module.h"
58 #include "wine/debug.h"
59 #include "user.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 HCURSOR hActiveCursor = 0; /* Active cursor */
70 static INT CURSOR_ShowCount = 0; /* Cursor display count */
71 static RECT CURSOR_ClipRect; /* Cursor clipping rect */
73 static HDC screen_dc;
75 /**********************************************************************
76 * ICONCACHE for cursors/icons loaded with LR_SHARED.
78 * FIXME: This should not be allocated on the system heap, but on a
79 * subsystem-global heap (i.e. one for all Win16 processes,
80 * and one for each Win32 process).
82 typedef struct tagICONCACHE
84 struct tagICONCACHE *next;
86 HMODULE hModule;
87 HRSRC hRsrc;
88 HRSRC hGroupRsrc;
89 HANDLE handle;
91 INT count;
93 } ICONCACHE;
95 static ICONCACHE *IconAnchor = NULL;
96 static CRITICAL_SECTION IconCrst = CRITICAL_SECTION_INIT("IconCrst");
97 static WORD ICON_HOTSPOT = 0x4242;
100 /***********************************************************************
101 * map_fileW
103 * Helper function to map a file to memory:
104 * name - file name
105 * [RETURN] ptr - pointer to mapped file
107 static void *map_fileW( LPCWSTR name )
109 HANDLE hFile, hMapping;
110 LPVOID ptr = NULL;
112 hFile = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL,
113 OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0 );
114 if (hFile != INVALID_HANDLE_VALUE)
116 hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
117 CloseHandle( hFile );
118 if (hMapping)
120 ptr = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
121 CloseHandle( hMapping );
124 return ptr;
128 /**********************************************************************
129 * CURSORICON_FindSharedIcon
131 static HANDLE CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
133 HANDLE handle = 0;
134 ICONCACHE *ptr;
136 EnterCriticalSection( &IconCrst );
138 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
139 if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
141 ptr->count++;
142 handle = ptr->handle;
143 break;
146 LeaveCriticalSection( &IconCrst );
148 return handle;
151 /*************************************************************************
152 * CURSORICON_FindCache
154 * Given a handle, find the corresponding cache element
156 * PARAMS
157 * Handle [I] handle to an Image
159 * RETURNS
160 * Success: The cache entry
161 * Failure: NULL
164 static ICONCACHE* CURSORICON_FindCache(HANDLE handle)
166 ICONCACHE *ptr;
167 ICONCACHE *pRet=NULL;
168 BOOL IsFound = FALSE;
169 int count;
171 EnterCriticalSection( &IconCrst );
173 for (count = 0, ptr = IconAnchor; ptr != NULL && !IsFound; ptr = ptr->next, count++ )
175 if ( handle == ptr->handle )
177 IsFound = TRUE;
178 pRet = ptr;
182 LeaveCriticalSection( &IconCrst );
184 return pRet;
187 /**********************************************************************
188 * CURSORICON_AddSharedIcon
190 static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HRSRC hGroupRsrc, HANDLE handle )
192 ICONCACHE *ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(ICONCACHE) );
193 if ( !ptr ) return;
195 ptr->hModule = hModule;
196 ptr->hRsrc = hRsrc;
197 ptr->handle = handle;
198 ptr->hGroupRsrc = hGroupRsrc;
199 ptr->count = 1;
201 EnterCriticalSection( &IconCrst );
202 ptr->next = IconAnchor;
203 IconAnchor = ptr;
204 LeaveCriticalSection( &IconCrst );
207 /**********************************************************************
208 * CURSORICON_DelSharedIcon
210 static INT CURSORICON_DelSharedIcon( HANDLE handle )
212 INT count = -1;
213 ICONCACHE *ptr;
215 EnterCriticalSection( &IconCrst );
217 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
218 if ( ptr->handle == handle )
220 if ( ptr->count > 0 ) ptr->count--;
221 count = ptr->count;
222 break;
225 LeaveCriticalSection( &IconCrst );
227 return count;
230 /**********************************************************************
231 * CURSORICON_FreeModuleIcons
233 void CURSORICON_FreeModuleIcons( HMODULE hModule )
235 ICONCACHE **ptr = &IconAnchor;
237 if ( HIWORD( hModule ) )
238 hModule = MapHModuleLS( hModule );
239 else
240 hModule = GetExePtr( hModule );
242 EnterCriticalSection( &IconCrst );
244 while ( *ptr )
246 if ( (*ptr)->hModule == hModule )
248 ICONCACHE *freePtr = *ptr;
249 *ptr = freePtr->next;
251 GlobalFree16( freePtr->handle );
252 HeapFree( GetProcessHeap(), 0, freePtr );
253 continue;
255 ptr = &(*ptr)->next;
258 LeaveCriticalSection( &IconCrst );
261 /**********************************************************************
262 * CURSORICON_FindBestIcon
264 * Find the icon closest to the requested size and number of colors.
266 static CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
267 int height, int colors )
269 int i;
270 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
271 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
272 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
274 if (dir->idCount < 1)
276 WARN_(icon)("Empty directory!\n" );
277 return NULL;
279 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
281 /* Find Best Fit */
282 iTotalDiff = 0xFFFFFFFF;
283 iColorDiff = 0xFFFFFFFF;
284 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
286 iTempXDiff = abs(width - entry->ResInfo.icon.bWidth);
287 iTempYDiff = abs(height - entry->ResInfo.icon.bHeight);
289 if(iTotalDiff > (iTempXDiff + iTempYDiff))
291 iXDiff = iTempXDiff;
292 iYDiff = iTempYDiff;
293 iTotalDiff = iXDiff + iYDiff;
297 /* Find Best Colors for Best Fit */
298 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
300 if(abs(width - entry->ResInfo.icon.bWidth) == iXDiff &&
301 abs(height - entry->ResInfo.icon.bHeight) == iYDiff)
303 iTempColorDiff = abs(colors - entry->ResInfo.icon.bColorCount);
304 if(iColorDiff > iTempColorDiff)
306 bestEntry = entry;
307 iColorDiff = iTempColorDiff;
312 return bestEntry;
316 /**********************************************************************
317 * CURSORICON_FindBestCursor
319 * Find the cursor closest to the requested size.
320 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
321 * ignored too
323 static CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
324 int width, int height, int color)
326 int i, maxwidth, maxheight;
327 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
329 if (dir->idCount < 1)
331 WARN_(cursor)("Empty directory!\n" );
332 return NULL;
334 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
336 /* Double height to account for AND and XOR masks */
338 height *= 2;
340 /* First find the largest one smaller than or equal to the requested size*/
342 maxwidth = maxheight = 0;
343 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
344 if ((entry->ResInfo.cursor.wWidth <= width) && (entry->ResInfo.cursor.wHeight <= height) &&
345 (entry->ResInfo.cursor.wWidth > maxwidth) && (entry->ResInfo.cursor.wHeight > maxheight) &&
346 (entry->wBitCount == 1))
348 bestEntry = entry;
349 maxwidth = entry->ResInfo.cursor.wWidth;
350 maxheight = entry->ResInfo.cursor.wHeight;
352 if (bestEntry) return bestEntry;
354 /* Now find the smallest one larger than the requested size */
356 maxwidth = maxheight = 255;
357 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
358 if ((entry->ResInfo.cursor.wWidth < maxwidth) && (entry->ResInfo.cursor.wHeight < maxheight) &&
359 (entry->wBitCount == 1))
361 bestEntry = entry;
362 maxwidth = entry->ResInfo.cursor.wWidth;
363 maxheight = entry->ResInfo.cursor.wHeight;
366 return bestEntry;
369 /*********************************************************************
370 * The main purpose of this function is to create fake resource directory
371 * and fake resource entries. There are several reasons for this:
372 * - CURSORICONDIR and CURSORICONFILEDIR differ in sizes and their
373 * fields
374 * There are some "bad" cursor files which do not have
375 * bColorCount initialized but instead one must read this info
376 * directly from corresponding DIB sections
377 * Note: wResId is index to array of pointer returned in ptrs (origin is 1)
379 BOOL CURSORICON_SimulateLoadingFromResourceW( LPWSTR filename, BOOL fCursor,
380 CURSORICONDIR **res, LPBYTE **ptr)
382 LPBYTE _free;
383 CURSORICONFILEDIR *bits;
384 int entries, size, i;
386 *res = NULL;
387 *ptr = NULL;
388 if (!(bits = map_fileW( filename ))) return FALSE;
390 /* FIXME: test for inimated icons
391 * hack to load the first icon from the *.ani file
393 if ( *(LPDWORD)bits==0x46464952 ) /* "RIFF" */
394 { LPBYTE pos = (LPBYTE) bits;
395 FIXME_(cursor)("Animated icons not correctly implemented! %p \n", bits);
397 for (;;)
398 { if (*(LPDWORD)pos==0x6e6f6369) /* "icon" */
399 { FIXME_(cursor)("icon entry found! %p\n", bits);
400 pos+=4;
401 if ( !*(LPWORD) pos==0x2fe) /* iconsize */
402 { goto fail;
404 bits=(CURSORICONFILEDIR*)(pos+4);
405 FIXME_(cursor)("icon size ok. offset=%p \n", bits);
406 break;
408 pos+=2;
409 if (pos>=(LPBYTE)bits+766) goto fail;
412 if (!(entries = bits->idCount)) goto fail;
413 size = sizeof(CURSORICONDIR) + sizeof(CURSORICONDIRENTRY) * (entries - 1);
414 _free = (LPBYTE) size;
416 for (i=0; i < entries; i++)
417 size += bits->idEntries[i].dwDIBSize + (fCursor ? sizeof(POINT16): 0);
419 if (!(*ptr = HeapAlloc( GetProcessHeap(), 0,
420 entries * sizeof (CURSORICONDIRENTRY*)))) goto fail;
421 if (!(*res = HeapAlloc( GetProcessHeap(), 0, size))) goto fail;
423 _free = (LPBYTE)(*res) + (int)_free;
424 memcpy((*res), bits, 6);
425 for (i=0; i<entries; i++)
427 ((LPBYTE*)(*ptr))[i] = _free;
428 if (fCursor) {
429 (*res)->idEntries[i].ResInfo.cursor.wWidth=bits->idEntries[i].bWidth;
430 (*res)->idEntries[i].ResInfo.cursor.wHeight=bits->idEntries[i].bHeight;
431 ((LPPOINT16)_free)->x=bits->idEntries[i].xHotspot;
432 ((LPPOINT16)_free)->y=bits->idEntries[i].yHotspot;
433 _free+=sizeof(POINT16);
434 } else {
435 (*res)->idEntries[i].ResInfo.icon.bWidth=bits->idEntries[i].bWidth;
436 (*res)->idEntries[i].ResInfo.icon.bHeight=bits->idEntries[i].bHeight;
437 (*res)->idEntries[i].ResInfo.icon.bColorCount = bits->idEntries[i].bColorCount;
439 (*res)->idEntries[i].wPlanes=1;
440 (*res)->idEntries[i].wBitCount = ((LPBITMAPINFOHEADER)((LPBYTE)bits +
441 bits->idEntries[i].dwDIBOffset))->biBitCount;
442 (*res)->idEntries[i].dwBytesInRes = bits->idEntries[i].dwDIBSize;
443 (*res)->idEntries[i].wResId=i+1;
445 memcpy(_free,(LPBYTE)bits +bits->idEntries[i].dwDIBOffset,
446 (*res)->idEntries[i].dwBytesInRes);
447 _free += (*res)->idEntries[i].dwBytesInRes;
449 UnmapViewOfFile( bits );
450 return TRUE;
451 fail:
452 if (*res) HeapFree( GetProcessHeap(), 0, *res );
453 if (*ptr) HeapFree( GetProcessHeap(), 0, *ptr );
454 UnmapViewOfFile( bits );
455 return FALSE;
459 /**********************************************************************
460 * CURSORICON_CreateFromResource
462 * Create a cursor or icon from in-memory resource template.
464 * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
465 * with cbSize parameter as well.
467 static HGLOBAL16 CURSORICON_CreateFromResource( HINSTANCE16 hInstance, HGLOBAL16 hObj, LPBYTE bits,
468 UINT cbSize, BOOL bIcon, DWORD dwVersion,
469 INT width, INT height, UINT loadflags )
471 static HDC hdcMem;
472 int sizeAnd, sizeXor;
473 HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
474 BITMAP bmpXor, bmpAnd;
475 POINT16 hotspot;
476 BITMAPINFO *bmi;
477 BOOL DoStretch;
478 INT size;
480 hotspot.x = ICON_HOTSPOT;
481 hotspot.y = ICON_HOTSPOT;
483 TRACE_(cursor)("%08x (%u bytes), ver %08x, %ix%i %s %s\n",
484 (unsigned)bits, cbSize, (unsigned)dwVersion, width, height,
485 bIcon ? "icon" : "cursor", (loadflags & LR_MONOCHROME) ? "mono" : "" );
486 if (dwVersion == 0x00020000)
488 FIXME_(cursor)("\t2.xx resources are not supported\n");
489 return 0;
492 if (bIcon)
493 bmi = (BITMAPINFO *)bits;
494 else /* get the hotspot */
496 POINT16 *pt = (POINT16 *)bits;
497 hotspot = *pt;
498 bmi = (BITMAPINFO *)(pt + 1);
500 size = DIB_BitmapInfoSize( bmi, DIB_RGB_COLORS );
502 if (!width) width = bmi->bmiHeader.biWidth;
503 if (!height) height = bmi->bmiHeader.biHeight/2;
504 DoStretch = (bmi->bmiHeader.biHeight/2 != height) ||
505 (bmi->bmiHeader.biWidth != width);
507 /* Check bitmap header */
509 if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
510 (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) ||
511 bmi->bmiHeader.biCompression != BI_RGB) )
513 WARN_(cursor)("\tinvalid resource bitmap header.\n");
514 return 0;
517 if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
518 if (screen_dc)
520 BITMAPINFO* pInfo;
522 /* Make sure we have room for the monochrome bitmap later on.
523 * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
524 * up to and including the biBitCount. In-memory icon resource
525 * format is as follows:
527 * BITMAPINFOHEADER icHeader // DIB header
528 * RGBQUAD icColors[] // Color table
529 * BYTE icXOR[] // DIB bits for XOR mask
530 * BYTE icAND[] // DIB bits for AND mask
533 if ((pInfo = (BITMAPINFO *)HeapAlloc( GetProcessHeap(), 0,
534 max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))))
536 memcpy( pInfo, bmi, size );
537 pInfo->bmiHeader.biHeight /= 2;
539 /* Create the XOR bitmap */
541 if (DoStretch) {
542 if(bIcon)
544 hXorBits = CreateCompatibleBitmap(screen_dc, width, height);
546 else
548 hXorBits = CreateBitmap(width, height, 1, 1, NULL);
550 if(hXorBits)
552 HBITMAP hOld;
553 BOOL res = FALSE;
555 if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
556 if (hdcMem) {
557 hOld = SelectObject(hdcMem, hXorBits);
558 res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
559 bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2,
560 (char*)bmi + size, pInfo, DIB_RGB_COLORS, SRCCOPY);
561 SelectObject(hdcMem, hOld);
563 if (!res) { DeleteObject(hXorBits); hXorBits = 0; }
565 } else hXorBits = CreateDIBitmap( screen_dc, &pInfo->bmiHeader,
566 CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS );
567 if( hXorBits )
569 char* xbits = (char *)bmi + size +
570 DIB_GetDIBImageBytes(bmi->bmiHeader.biWidth,
571 bmi->bmiHeader.biHeight,
572 bmi->bmiHeader.biBitCount) / 2;
574 pInfo->bmiHeader.biBitCount = 1;
575 if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
577 RGBQUAD *rgb = pInfo->bmiColors;
579 pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
580 rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
581 rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
582 rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
584 else
586 RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
588 rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
589 rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
592 /* Create the AND bitmap */
594 if (DoStretch) {
595 if ((hAndBits = CreateBitmap(width, height, 1, 1, NULL))) {
596 HBITMAP hOld;
597 BOOL res = FALSE;
599 if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
600 if (hdcMem) {
601 hOld = SelectObject(hdcMem, hAndBits);
602 res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
603 pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight,
604 xbits, pInfo, DIB_RGB_COLORS, SRCCOPY);
605 SelectObject(hdcMem, hOld);
607 if (!res) { DeleteObject(hAndBits); hAndBits = 0; }
609 } else hAndBits = CreateDIBitmap( screen_dc, &pInfo->bmiHeader,
610 CBM_INIT, xbits, pInfo, DIB_RGB_COLORS );
612 if( !hAndBits ) DeleteObject( hXorBits );
614 HeapFree( GetProcessHeap(), 0, pInfo );
618 if( !hXorBits || !hAndBits )
620 WARN_(cursor)("\tunable to create an icon bitmap.\n");
621 return 0;
624 /* Now create the CURSORICONINFO structure */
625 GetObjectA( hXorBits, sizeof(bmpXor), &bmpXor );
626 GetObjectA( hAndBits, sizeof(bmpAnd), &bmpAnd );
627 sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
628 sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
630 if (hObj) hObj = GlobalReAlloc16( hObj,
631 sizeof(CURSORICONINFO) + sizeXor + sizeAnd, GMEM_MOVEABLE );
632 if (!hObj) hObj = GlobalAlloc16( GMEM_MOVEABLE,
633 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
634 if (hObj)
636 CURSORICONINFO *info;
638 /* Make it owned by the module */
639 if (hInstance) hInstance = GetExePtr(hInstance);
640 FarSetOwner16( hObj, hInstance );
642 info = (CURSORICONINFO *)GlobalLock16( hObj );
643 info->ptHotSpot.x = hotspot.x;
644 info->ptHotSpot.y = hotspot.y;
645 info->nWidth = bmpXor.bmWidth;
646 info->nHeight = bmpXor.bmHeight;
647 info->nWidthBytes = bmpXor.bmWidthBytes;
648 info->bPlanes = bmpXor.bmPlanes;
649 info->bBitsPerPixel = bmpXor.bmBitsPixel;
651 /* Transfer the bitmap bits to the CURSORICONINFO structure */
653 GetBitmapBits( hAndBits, sizeAnd, (char *)(info + 1) );
654 GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
655 GlobalUnlock16( hObj );
658 DeleteObject( hAndBits );
659 DeleteObject( hXorBits );
660 return hObj;
664 /**********************************************************************
665 * CreateIconFromResourceEx (USER.450)
667 * FIXME: not sure about exact parameter types
669 HICON16 WINAPI CreateIconFromResourceEx16( LPBYTE bits, UINT16 cbSize, BOOL16 bIcon,
670 DWORD dwVersion, INT16 width, INT16 height, UINT16 cFlag )
672 return CreateIconFromResourceEx(bits, cbSize, bIcon, dwVersion,
673 width, height, cFlag);
677 /**********************************************************************
678 * CreateIconFromResource (USER32.@)
680 HICON WINAPI CreateIconFromResource( LPBYTE bits, UINT cbSize,
681 BOOL bIcon, DWORD dwVersion)
683 return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
687 /**********************************************************************
688 * CreateIconFromResourceEx (USER32.@)
690 HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
691 BOOL bIcon, DWORD dwVersion,
692 INT width, INT height,
693 UINT cFlag )
695 return CURSORICON_CreateFromResource( 0, 0, bits, cbSize, bIcon, dwVersion,
696 width, height, cFlag );
699 /**********************************************************************
700 * CURSORICON_Load
702 * Load a cursor or icon from resource or file.
704 HGLOBAL CURSORICON_Load( HINSTANCE hInstance, LPCWSTR name,
705 INT width, INT height, INT colors,
706 BOOL fCursor, UINT loadflags )
708 HANDLE handle = 0, h = 0;
709 HANDLE hRsrc;
710 CURSORICONDIR *dir;
711 CURSORICONDIRENTRY *dirEntry;
712 LPBYTE bits;
714 if ( loadflags & LR_LOADFROMFILE ) /* Load from file */
716 LPBYTE *ptr;
717 if (!CURSORICON_SimulateLoadingFromResourceW((LPWSTR)name, fCursor, &dir, &ptr))
718 return 0;
719 if (fCursor)
720 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(dir, width, height, 1);
721 else
722 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(dir, width, height, colors);
723 bits = ptr[dirEntry->wResId-1];
724 h = CURSORICON_CreateFromResource( 0, 0, bits, dirEntry->dwBytesInRes,
725 !fCursor, 0x00030000, width, height, loadflags);
726 HeapFree( GetProcessHeap(), 0, dir );
727 HeapFree( GetProcessHeap(), 0, ptr );
729 else /* Load from resource */
731 HANDLE hGroupRsrc;
732 WORD wResId;
733 DWORD dwBytesInRes;
735 if (!hInstance) /* Load OEM cursor/icon */
737 if (!(hInstance = GetModuleHandleA( "user32.dll" ))) return 0;
740 /* Normalize hInstance (must be uniquely represented for icon cache) */
742 if ( HIWORD( hInstance ) )
743 hInstance = MapHModuleLS( hInstance );
744 else
745 hInstance = GetExePtr( hInstance );
747 /* Get directory resource ID */
749 if (!(hRsrc = FindResourceW( hInstance, name,
750 fCursor ? RT_GROUP_CURSORW : RT_GROUP_ICONW )))
751 return 0;
752 hGroupRsrc = hRsrc;
754 /* Find the best entry in the directory */
756 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
757 if (!(dir = (CURSORICONDIR*)LockResource( handle ))) return 0;
758 if (fCursor)
759 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor( dir,
760 width, height, 1);
761 else
762 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon( dir,
763 width, height, colors );
764 if (!dirEntry) return 0;
765 wResId = dirEntry->wResId;
766 dwBytesInRes = dirEntry->dwBytesInRes;
767 FreeResource( handle );
769 /* Load the resource */
771 if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
772 fCursor ? RT_CURSORW : RT_ICONW ))) return 0;
774 /* If shared icon, check whether it was already loaded */
775 if ( (loadflags & LR_SHARED)
776 && (h = CURSORICON_FindSharedIcon( hInstance, hRsrc ) ) != 0 )
777 return h;
779 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
780 bits = (LPBYTE)LockResource( handle );
781 h = CURSORICON_CreateFromResource( 0, 0, bits, dwBytesInRes,
782 !fCursor, 0x00030000, width, height, loadflags);
783 FreeResource( handle );
785 /* If shared icon, add to icon cache */
787 if ( h && (loadflags & LR_SHARED) )
788 CURSORICON_AddSharedIcon( hInstance, hRsrc, hGroupRsrc, h );
791 return h;
794 /***********************************************************************
795 * CURSORICON_Copy
797 * Make a copy of a cursor or icon.
799 static HGLOBAL16 CURSORICON_Copy( HINSTANCE16 hInstance, HGLOBAL16 handle )
801 char *ptrOld, *ptrNew;
802 int size;
803 HGLOBAL16 hNew;
805 if (!(ptrOld = (char *)GlobalLock16( handle ))) return 0;
806 if (hInstance && !(hInstance = GetExePtr( hInstance ))) return 0;
807 size = GlobalSize16( handle );
808 hNew = GlobalAlloc16( GMEM_MOVEABLE, size );
809 FarSetOwner16( hNew, hInstance );
810 ptrNew = (char *)GlobalLock16( hNew );
811 memcpy( ptrNew, ptrOld, size );
812 GlobalUnlock16( handle );
813 GlobalUnlock16( hNew );
814 return hNew;
817 /*************************************************************************
818 * CURSORICON_ExtCopy
820 * Copies an Image from the Cache if LR_COPYFROMRESOURCE is specified
822 * PARAMS
823 * Handle [I] handle to an Image
824 * nType [I] Type of Handle (IMAGE_CURSOR | IMAGE_ICON)
825 * iDesiredCX [I] The Desired width of the Image
826 * iDesiredCY [I] The desired height of the Image
827 * nFlags [I] The flags from CopyImage
829 * RETURNS
830 * Success: The new handle of the Image
832 * NOTES
833 * LR_COPYDELETEORG and LR_MONOCHROME are currently not implemented.
834 * LR_MONOCHROME should be implemented by CURSORICON_CreateFromResource.
835 * LR_COPYFROMRESOURCE will only work if the Image is in the Cache.
840 HGLOBAL CURSORICON_ExtCopy(HGLOBAL Handle, UINT nType,
841 INT iDesiredCX, INT iDesiredCY,
842 UINT nFlags)
844 HGLOBAL16 hNew=0;
846 TRACE_(icon)("Handle %u, uType %u, iDesiredCX %i, iDesiredCY %i, nFlags %u\n",
847 Handle, nType, iDesiredCX, iDesiredCY, nFlags);
849 if(Handle == 0)
851 return 0;
854 /* Best Fit or Monochrome */
855 if( (nFlags & LR_COPYFROMRESOURCE
856 && (iDesiredCX > 0 || iDesiredCY > 0))
857 || nFlags & LR_MONOCHROME)
859 ICONCACHE* pIconCache = CURSORICON_FindCache(Handle);
861 /* Not Found in Cache, then do a straight copy
863 if(pIconCache == NULL)
865 hNew = CURSORICON_Copy(0, Handle);
866 if(nFlags & LR_COPYFROMRESOURCE)
868 TRACE_(icon)("LR_COPYFROMRESOURCE: Failed to load from cache\n");
871 else
873 int iTargetCY = iDesiredCY, iTargetCX = iDesiredCX;
874 LPBYTE pBits;
875 HANDLE hMem;
876 HRSRC hRsrc;
877 DWORD dwBytesInRes;
878 WORD wResId;
879 CURSORICONDIR *pDir;
880 CURSORICONDIRENTRY *pDirEntry;
881 BOOL bIsIcon = (nType == IMAGE_ICON);
883 /* Completing iDesiredCX CY for Monochrome Bitmaps if needed
885 if(((nFlags & LR_MONOCHROME) && !(nFlags & LR_COPYFROMRESOURCE))
886 || (iDesiredCX == 0 && iDesiredCY == 0))
888 iDesiredCY = GetSystemMetrics(bIsIcon ?
889 SM_CYICON : SM_CYCURSOR);
890 iDesiredCX = GetSystemMetrics(bIsIcon ?
891 SM_CXICON : SM_CXCURSOR);
894 /* Retrieve the CURSORICONDIRENTRY
896 if (!(hMem = LoadResource( pIconCache->hModule ,
897 pIconCache->hGroupRsrc)))
899 return 0;
901 if (!(pDir = (CURSORICONDIR*)LockResource( hMem )))
903 return 0;
906 /* Find Best Fit
908 if(bIsIcon)
910 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(
911 pDir, iDesiredCX, iDesiredCY, 256);
913 else
915 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(
916 pDir, iDesiredCX, iDesiredCY, 1);
919 wResId = pDirEntry->wResId;
920 dwBytesInRes = pDirEntry->dwBytesInRes;
921 FreeResource(hMem);
923 TRACE_(icon)("ResID %u, BytesInRes %lu, Width %d, Height %d DX %d, DY %d\n",
924 wResId, dwBytesInRes, pDirEntry->ResInfo.icon.bWidth,
925 pDirEntry->ResInfo.icon.bHeight, iDesiredCX, iDesiredCY);
927 /* Get the Best Fit
929 if (!(hRsrc = FindResourceW(pIconCache->hModule ,
930 MAKEINTRESOURCEW(wResId), bIsIcon ? RT_ICONW : RT_CURSORW)))
932 return 0;
934 if (!(hMem = LoadResource( pIconCache->hModule , hRsrc )))
936 return 0;
939 pBits = (LPBYTE)LockResource( hMem );
941 if(nFlags & LR_DEFAULTSIZE)
943 iTargetCY = GetSystemMetrics(SM_CYICON);
944 iTargetCX = GetSystemMetrics(SM_CXICON);
947 /* Create a New Icon with the proper dimension
949 hNew = CURSORICON_CreateFromResource( 0, 0, pBits, dwBytesInRes,
950 bIsIcon, 0x00030000, iTargetCX, iTargetCY, nFlags);
951 FreeResource(hMem);
954 else hNew = CURSORICON_Copy(0, Handle);
955 return hNew;
958 /***********************************************************************
959 * CURSORICON_IconToCursor
961 * Converts bitmap to mono and truncates if icon is too large (should
962 * probably do StretchBlt() instead).
964 HCURSOR16 CURSORICON_IconToCursor(HICON16 hIcon, BOOL bSemiTransparent)
966 HCURSOR16 hRet = 0;
967 CURSORICONINFO *pIcon = NULL;
969 if(hIcon)
970 if (!(pIcon = (CURSORICONINFO*)GlobalLock16( hIcon ))) return FALSE;
971 if (pIcon->bPlanes * pIcon->bBitsPerPixel == 1)
973 hRet = CURSORICON_Copy( 0, hIcon );
976 pIcon = GlobalLock16(hRet);
978 pIcon->ptHotSpot.x = pIcon->ptHotSpot.y = 15;
980 GlobalUnlock16(hRet);
982 else
984 BYTE pAndBits[128];
985 BYTE pXorBits[128];
986 int maxx, maxy, ix, iy, bpp = pIcon->bBitsPerPixel;
987 BYTE* psPtr, *pxbPtr = pXorBits;
988 unsigned xor_width, and_width, val_base = 0xffffffff >> (32 - bpp);
989 BYTE* pbc = NULL;
991 CURSORICONINFO cI;
993 TRACE_(icon)("[%04x] %ix%i %ibpp (bogus %ibps)\n",
994 hIcon, pIcon->nWidth, pIcon->nHeight, pIcon->bBitsPerPixel, pIcon->nWidthBytes );
996 xor_width = BITMAP_GetWidthBytes( pIcon->nWidth, bpp );
997 and_width = BITMAP_GetWidthBytes( pIcon->nWidth, 1 );
998 psPtr = (BYTE *)(pIcon + 1) + pIcon->nHeight * and_width;
1000 memset(pXorBits, 0, 128);
1001 cI.bBitsPerPixel = 1; cI.bPlanes = 1;
1002 cI.ptHotSpot.x = cI.ptHotSpot.y = 15;
1003 cI.nWidth = 32; cI.nHeight = 32;
1004 cI.nWidthBytes = 4; /* 32x1bpp */
1006 maxx = (pIcon->nWidth > 32) ? 32 : pIcon->nWidth;
1007 maxy = (pIcon->nHeight > 32) ? 32 : pIcon->nHeight;
1009 for( iy = 0; iy < maxy; iy++ )
1011 unsigned shift = iy % 2;
1013 memcpy( pAndBits + iy * 4, (BYTE *)(pIcon + 1) + iy * and_width,
1014 (and_width > 4) ? 4 : and_width );
1015 for( ix = 0; ix < maxx; ix++ )
1017 if( bSemiTransparent && ((ix+shift)%2) )
1019 /* set AND bit, XOR bit stays 0 */
1021 pbc = pAndBits + iy * 4 + ix/8;
1022 *pbc |= 0x80 >> (ix%8);
1024 else
1026 /* keep AND bit, set XOR bit */
1028 unsigned *psc = (unsigned*)(psPtr + (ix * bpp)/8);
1029 unsigned val = ((*psc) >> (ix * bpp)%8) & val_base;
1030 if(PALETTE_Driver && !PALETTE_Driver->pIsDark(val))
1032 pbc = pxbPtr + ix/8;
1033 *pbc |= 0x80 >> (ix%8);
1037 psPtr += xor_width;
1038 pxbPtr += 4;
1041 hRet = CreateCursorIconIndirect16( 0 , &cI, pAndBits, pXorBits);
1043 if( !hRet ) /* fall back on default drag cursor */
1044 hRet = CURSORICON_Copy( 0 ,
1045 CURSORICON_Load(0,MAKEINTRESOURCEW(OCR_DRAGOBJECT),
1046 GetSystemMetrics(SM_CXCURSOR),
1047 GetSystemMetrics(SM_CYCURSOR), 1, TRUE, 0) );
1050 return hRet;
1054 /***********************************************************************
1055 * LoadCursor (USER.173)
1057 HCURSOR16 WINAPI LoadCursor16( HINSTANCE16 hInstance, LPCSTR name )
1059 return LoadCursorA( hInstance, name );
1063 /***********************************************************************
1064 * LoadIcon (USER.174)
1066 HICON16 WINAPI LoadIcon16( HINSTANCE16 hInstance, LPCSTR name )
1068 return LoadIconA( hInstance, name );
1072 /***********************************************************************
1073 * CreateCursor (USER.406)
1075 HCURSOR16 WINAPI CreateCursor16( HINSTANCE16 hInstance,
1076 INT16 xHotSpot, INT16 yHotSpot,
1077 INT16 nWidth, INT16 nHeight,
1078 LPCVOID lpANDbits, LPCVOID lpXORbits )
1080 CURSORICONINFO info;
1082 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1083 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1085 info.ptHotSpot.x = xHotSpot;
1086 info.ptHotSpot.y = yHotSpot;
1087 info.nWidth = nWidth;
1088 info.nHeight = nHeight;
1089 info.nWidthBytes = 0;
1090 info.bPlanes = 1;
1091 info.bBitsPerPixel = 1;
1093 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1097 /***********************************************************************
1098 * CreateCursor (USER32.@)
1100 HCURSOR WINAPI CreateCursor( HINSTANCE hInstance,
1101 INT xHotSpot, INT yHotSpot,
1102 INT nWidth, INT nHeight,
1103 LPCVOID lpANDbits, LPCVOID lpXORbits )
1105 CURSORICONINFO info;
1107 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1108 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1110 info.ptHotSpot.x = xHotSpot;
1111 info.ptHotSpot.y = yHotSpot;
1112 info.nWidth = nWidth;
1113 info.nHeight = nHeight;
1114 info.nWidthBytes = 0;
1115 info.bPlanes = 1;
1116 info.bBitsPerPixel = 1;
1118 return CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
1122 /***********************************************************************
1123 * CreateIcon (USER.407)
1125 HICON16 WINAPI CreateIcon16( HINSTANCE16 hInstance, INT16 nWidth,
1126 INT16 nHeight, BYTE bPlanes, BYTE bBitsPixel,
1127 LPCVOID lpANDbits, LPCVOID lpXORbits )
1129 CURSORICONINFO info;
1131 TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1132 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
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 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1146 /***********************************************************************
1147 * CreateIcon (USER32.@)
1149 * Creates an icon based on the specified bitmaps. The bitmaps must be
1150 * provided in a device dependent format and will be resized to
1151 * (SM_CXICON,SM_CYICON) and depth converted to match the screen's color
1152 * depth. The provided bitmaps must be top-down bitmaps.
1153 * Although Windows does not support 15bpp(*) this API must support it
1154 * for Winelib applications.
1156 * (*) Windows does not support 15bpp but it supports the 555 RGB 16bpp
1157 * format!
1159 * BUGS
1161 * - The provided bitmaps are not resized!
1162 * - The documentation says the lpXORbits bitmap must be in a device
1163 * dependent format. But we must still resize it and perform depth
1164 * conversions if necessary.
1165 * - I'm a bit unsure about the how the 'device dependent format' thing works.
1166 * I did some tests on windows and found that if you provide a 16bpp bitmap
1167 * in lpXORbits, then its format but be 565 RGB if the screen's bit depth
1168 * is 16bpp but it must be 555 RGB if the screen's bit depth is anything
1169 * else. I don't know if this is part of the GDI specs or if this is a
1170 * quirk of the graphics card driver.
1171 * - You may think that we check whether the bit depths match or not
1172 * as an optimization. But the truth is that the conversion using
1173 * CreateDIBitmap does not work for some bit depth (e.g. 8bpp) and I have
1174 * no idea why.
1175 * - I'm pretty sure that all the things we do in CreateIcon should
1176 * also be done in CreateIconIndirect...
1178 HICON WINAPI CreateIcon(
1179 HINSTANCE hInstance, /* [in] the application's hInstance, currently unused */
1180 INT nWidth, /* [in] the width of the provided bitmaps */
1181 INT nHeight, /* [in] the height of the provided bitmaps */
1182 BYTE bPlanes, /* [in] the number of planes in the provided bitmaps */
1183 BYTE bBitsPixel, /* [in] the number of bits per pixel of the lpXORbits bitmap */
1184 LPCVOID lpANDbits, /* [in] a monochrome bitmap representing the icon's mask */
1185 LPCVOID lpXORbits) /* [in] the icon's 'color' bitmap */
1187 HICON hIcon;
1188 HDC hdc;
1190 TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1191 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1193 hdc=GetDC(0);
1194 if (!hdc)
1195 return 0;
1197 if (GetDeviceCaps(hdc,BITSPIXEL)==bBitsPixel) {
1198 CURSORICONINFO info;
1200 info.ptHotSpot.x = ICON_HOTSPOT;
1201 info.ptHotSpot.y = ICON_HOTSPOT;
1202 info.nWidth = nWidth;
1203 info.nHeight = nHeight;
1204 info.nWidthBytes = 0;
1205 info.bPlanes = bPlanes;
1206 info.bBitsPerPixel = bBitsPixel;
1208 hIcon=CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
1209 } else {
1210 ICONINFO iinfo;
1211 BITMAPINFO bmi;
1213 iinfo.fIcon=TRUE;
1214 iinfo.xHotspot=ICON_HOTSPOT;
1215 iinfo.yHotspot=ICON_HOTSPOT;
1216 iinfo.hbmMask=CreateBitmap(nWidth,nHeight,1,1,lpANDbits);
1218 bmi.bmiHeader.biSize=sizeof(bmi.bmiHeader);
1219 bmi.bmiHeader.biWidth=nWidth;
1220 bmi.bmiHeader.biHeight=-nHeight;
1221 bmi.bmiHeader.biPlanes=bPlanes;
1222 bmi.bmiHeader.biBitCount=bBitsPixel;
1223 bmi.bmiHeader.biCompression=BI_RGB;
1224 bmi.bmiHeader.biSizeImage=0;
1225 bmi.bmiHeader.biXPelsPerMeter=0;
1226 bmi.bmiHeader.biYPelsPerMeter=0;
1227 bmi.bmiHeader.biClrUsed=0;
1228 bmi.bmiHeader.biClrImportant=0;
1230 iinfo.hbmColor = CreateDIBitmap( hdc, &bmi.bmiHeader,
1231 CBM_INIT, lpXORbits,
1232 &bmi, DIB_RGB_COLORS );
1234 hIcon=CreateIconIndirect(&iinfo);
1235 DeleteObject(iinfo.hbmMask);
1236 DeleteObject(iinfo.hbmColor);
1238 ReleaseDC(0,hdc);
1239 return hIcon;
1243 /***********************************************************************
1244 * CreateCursorIconIndirect (USER.408)
1246 HGLOBAL16 WINAPI CreateCursorIconIndirect16( HINSTANCE16 hInstance,
1247 CURSORICONINFO *info,
1248 LPCVOID lpANDbits,
1249 LPCVOID lpXORbits )
1251 HGLOBAL16 handle;
1252 char *ptr;
1253 int sizeAnd, sizeXor;
1255 hInstance = GetExePtr( hInstance ); /* Make it a module handle */
1256 if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
1257 info->nWidthBytes = BITMAP_GetWidthBytes(info->nWidth,info->bBitsPerPixel);
1258 sizeXor = info->nHeight * info->nWidthBytes;
1259 sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
1260 if (!(handle = GlobalAlloc16( GMEM_MOVEABLE,
1261 sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
1262 return 0;
1263 FarSetOwner16( handle, hInstance );
1264 ptr = (char *)GlobalLock16( handle );
1265 memcpy( ptr, info, sizeof(*info) );
1266 memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
1267 memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
1268 GlobalUnlock16( handle );
1269 return handle;
1273 /***********************************************************************
1274 * CopyIcon (USER.368)
1276 HICON16 WINAPI CopyIcon16( HINSTANCE16 hInstance, HICON16 hIcon )
1278 TRACE_(icon)("%04x %04x\n", hInstance, hIcon );
1279 return CURSORICON_Copy( hInstance, hIcon );
1283 /***********************************************************************
1284 * CopyIcon (USER32.@)
1286 HICON WINAPI CopyIcon( HICON hIcon )
1288 TRACE_(icon)("%04x\n", hIcon );
1289 return CURSORICON_Copy( 0, hIcon );
1293 /***********************************************************************
1294 * CopyCursor (USER.369)
1296 HCURSOR16 WINAPI CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
1298 TRACE_(cursor)("%04x %04x\n", hInstance, hCursor );
1299 return CURSORICON_Copy( hInstance, hCursor );
1302 /**********************************************************************
1303 * DestroyIcon32 (USER.610)
1304 * DestroyIcon32 (USER32.@)
1306 * This routine is actually exported from Win95 USER under the name
1307 * DestroyIcon32 ... The behaviour implemented here should mimic
1308 * the Win95 one exactly, especially the return values, which
1309 * depend on the setting of various flags.
1311 WORD WINAPI DestroyIcon32( HGLOBAL16 handle, UINT16 flags )
1313 WORD retv;
1315 TRACE_(icon)("(%04x, %04x)\n", handle, flags );
1317 /* Check whether destroying active cursor */
1319 if ( hActiveCursor == handle )
1321 WARN_(cursor)("Destroying active cursor!\n" );
1322 SetCursor( 0 );
1325 /* Try shared cursor/icon first */
1327 if ( !(flags & CID_NONSHARED) )
1329 INT count = CURSORICON_DelSharedIcon( handle );
1331 if ( count != -1 )
1332 return (flags & CID_WIN32)? TRUE : (count == 0);
1334 /* FIXME: OEM cursors/icons should be recognized */
1337 /* Now assume non-shared cursor/icon */
1339 retv = GlobalFree16( handle );
1340 return (flags & CID_RESOURCE)? retv : TRUE;
1343 /***********************************************************************
1344 * DestroyIcon (USER.457)
1346 BOOL16 WINAPI DestroyIcon16( HICON16 hIcon )
1348 return DestroyIcon32( hIcon, 0 );
1351 /***********************************************************************
1352 * DestroyIcon (USER32.@)
1354 BOOL WINAPI DestroyIcon( HICON hIcon )
1356 return DestroyIcon32( hIcon, CID_WIN32 );
1359 /***********************************************************************
1360 * DestroyCursor (USER.458)
1362 BOOL16 WINAPI DestroyCursor16( HCURSOR16 hCursor )
1364 return DestroyIcon32( hCursor, 0 );
1367 /***********************************************************************
1368 * DestroyCursor (USER32.@)
1370 BOOL WINAPI DestroyCursor( HCURSOR hCursor )
1372 return DestroyIcon32( hCursor, CID_WIN32 );
1376 /***********************************************************************
1377 * DrawIcon (USER.84)
1379 BOOL16 WINAPI DrawIcon16( HDC16 hdc, INT16 x, INT16 y, HICON16 hIcon )
1381 return DrawIcon( hdc, x, y, hIcon );
1385 /***********************************************************************
1386 * DrawIcon (USER32.@)
1388 BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
1390 CURSORICONINFO *ptr;
1391 HDC hMemDC;
1392 HBITMAP hXorBits, hAndBits;
1393 COLORREF oldFg, oldBg;
1395 if (!(ptr = (CURSORICONINFO *)GlobalLock16( hIcon ))) return FALSE;
1396 if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
1397 hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1,
1398 (char *)(ptr+1) );
1399 hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
1400 ptr->bBitsPerPixel, (char *)(ptr + 1)
1401 + ptr->nHeight * BITMAP_GetWidthBytes(ptr->nWidth,1) );
1402 oldFg = SetTextColor( hdc, RGB(0,0,0) );
1403 oldBg = SetBkColor( hdc, RGB(255,255,255) );
1405 if (hXorBits && hAndBits)
1407 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1408 BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
1409 SelectObject( hMemDC, hXorBits );
1410 BitBlt(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
1411 SelectObject( hMemDC, hBitTemp );
1413 DeleteDC( hMemDC );
1414 if (hXorBits) DeleteObject( hXorBits );
1415 if (hAndBits) DeleteObject( hAndBits );
1416 GlobalUnlock16( hIcon );
1417 SetTextColor( hdc, oldFg );
1418 SetBkColor( hdc, oldBg );
1419 return TRUE;
1423 /***********************************************************************
1424 * IconSize (USER.86)
1426 * See "Undocumented Windows". Used by W2.0 paint.exe.
1428 DWORD WINAPI IconSize16( void )
1430 return MAKELONG(GetSystemMetrics(SM_CYICON), GetSystemMetrics(SM_CXICON));
1434 /***********************************************************************
1435 * DumpIcon (USER.459)
1437 DWORD WINAPI DumpIcon16( SEGPTR pInfo, WORD *lpLen,
1438 SEGPTR *lpXorBits, SEGPTR *lpAndBits )
1440 CURSORICONINFO *info = MapSL( pInfo );
1441 int sizeAnd, sizeXor;
1443 if (!info) return 0;
1444 sizeXor = info->nHeight * info->nWidthBytes;
1445 sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
1446 if (lpAndBits) *lpAndBits = pInfo + sizeof(CURSORICONINFO);
1447 if (lpXorBits) *lpXorBits = pInfo + sizeof(CURSORICONINFO) + sizeAnd;
1448 if (lpLen) *lpLen = sizeof(CURSORICONINFO) + sizeAnd + sizeXor;
1449 return MAKELONG( sizeXor, sizeXor );
1453 /***********************************************************************
1454 * SetCursor (USER.69)
1456 HCURSOR16 WINAPI SetCursor16( HCURSOR16 hCursor )
1458 return (HCURSOR16)SetCursor( hCursor );
1462 /***********************************************************************
1463 * SetCursor (USER32.@)
1464 * RETURNS:
1465 * A handle to the previous cursor shape.
1467 HCURSOR WINAPI SetCursor(
1468 HCURSOR hCursor /* [in] Handle of cursor to show */
1470 HCURSOR hOldCursor;
1472 if (hCursor == hActiveCursor) return hActiveCursor; /* No change */
1473 TRACE_(cursor)("%04x\n", hCursor );
1474 hOldCursor = hActiveCursor;
1475 hActiveCursor = hCursor;
1476 /* Change the cursor shape only if it is visible */
1477 if (CURSOR_ShowCount >= 0)
1479 USER_Driver.pSetCursor( (CURSORICONINFO*)GlobalLock16( hActiveCursor ) );
1480 GlobalUnlock16( hActiveCursor );
1482 return hOldCursor;
1486 /***********************************************************************
1487 * ShowCursor (USER.71)
1489 INT16 WINAPI ShowCursor16( BOOL16 bShow )
1491 return ShowCursor( bShow );
1495 /***********************************************************************
1496 * ShowCursor (USER32.@)
1498 INT WINAPI ShowCursor( BOOL bShow )
1500 TRACE_(cursor)("%d, count=%d\n",
1501 bShow, CURSOR_ShowCount );
1503 if (bShow)
1505 if (++CURSOR_ShowCount == 0) /* Show it */
1507 USER_Driver.pSetCursor( (CURSORICONINFO*)GlobalLock16( hActiveCursor ) );
1508 GlobalUnlock16( hActiveCursor );
1511 else
1513 if (--CURSOR_ShowCount == -1) /* Hide it */
1514 USER_Driver.pSetCursor( NULL );
1516 return CURSOR_ShowCount;
1520 /***********************************************************************
1521 * GetCursor (USER.247)
1523 HCURSOR16 WINAPI GetCursor16(void)
1525 return hActiveCursor;
1529 /***********************************************************************
1530 * GetCursor (USER32.@)
1532 HCURSOR WINAPI GetCursor(void)
1534 return hActiveCursor;
1538 /***********************************************************************
1539 * ClipCursor (USER.16)
1541 BOOL16 WINAPI ClipCursor16( const RECT16 *rect )
1543 if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1544 else CONV_RECT16TO32( rect, &CURSOR_ClipRect );
1545 return TRUE;
1549 /***********************************************************************
1550 * ClipCursor (USER32.@)
1552 BOOL WINAPI ClipCursor( const RECT *rect )
1554 if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1555 else CopyRect( &CURSOR_ClipRect, rect );
1556 return TRUE;
1560 /***********************************************************************
1561 * GetClipCursor (USER.309)
1563 void WINAPI GetClipCursor16( RECT16 *rect )
1565 if (rect) CONV_RECT32TO16( &CURSOR_ClipRect, rect );
1569 /***********************************************************************
1570 * GetClipCursor (USER32.@)
1572 BOOL WINAPI GetClipCursor( RECT *rect )
1574 if (rect)
1576 CopyRect( rect, &CURSOR_ClipRect );
1577 return TRUE;
1579 return FALSE;
1582 /**********************************************************************
1583 * LookupIconIdFromDirectoryEx (USER.364)
1585 * FIXME: exact parameter sizes
1587 INT16 WINAPI LookupIconIdFromDirectoryEx16( LPBYTE xdir, BOOL16 bIcon,
1588 INT16 width, INT16 height, UINT16 cFlag )
1590 CURSORICONDIR *dir = (CURSORICONDIR*)xdir;
1591 UINT16 retVal = 0;
1592 if( dir && !dir->idReserved && (dir->idType & 3) )
1594 CURSORICONDIRENTRY* entry;
1595 HDC hdc;
1596 UINT palEnts;
1597 int colors;
1598 hdc = GetDC(0);
1599 palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
1600 if (palEnts == 0)
1601 palEnts = 256;
1602 colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
1604 ReleaseDC(0, hdc);
1606 if( bIcon )
1607 entry = CURSORICON_FindBestIcon( dir, width, height, colors );
1608 else
1609 entry = CURSORICON_FindBestCursor( dir, width, height, 1);
1611 if( entry ) retVal = entry->wResId;
1613 else WARN_(cursor)("invalid resource directory\n");
1614 return retVal;
1617 /**********************************************************************
1618 * LookupIconIdFromDirectoryEx (USER32.@)
1620 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE dir, BOOL bIcon,
1621 INT width, INT height, UINT cFlag )
1623 return LookupIconIdFromDirectoryEx16( dir, bIcon, width, height, cFlag );
1626 /**********************************************************************
1627 * LookupIconIdFromDirectory (USER.?)
1629 INT16 WINAPI LookupIconIdFromDirectory16( LPBYTE dir, BOOL16 bIcon )
1631 return LookupIconIdFromDirectoryEx16( dir, bIcon,
1632 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1633 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1636 /**********************************************************************
1637 * LookupIconIdFromDirectory (USER32.@)
1639 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1641 return LookupIconIdFromDirectoryEx( dir, bIcon,
1642 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1643 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1646 /**********************************************************************
1647 * GetIconID (USER.455)
1649 WORD WINAPI GetIconID16( HGLOBAL16 hResource, DWORD resType )
1651 LPBYTE lpDir = (LPBYTE)GlobalLock16(hResource);
1653 TRACE_(cursor)("hRes=%04x, entries=%i\n",
1654 hResource, lpDir ? ((CURSORICONDIR*)lpDir)->idCount : 0);
1656 switch(resType)
1658 case RT_CURSOR16:
1659 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, FALSE,
1660 GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1661 case RT_ICON16:
1662 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, TRUE,
1663 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0 );
1664 default:
1665 WARN_(cursor)("invalid res type %ld\n", resType );
1667 return 0;
1670 /**********************************************************************
1671 * LoadCursorIconHandler (USER.336)
1673 * Supposed to load resources of Windows 2.x applications.
1675 HGLOBAL16 WINAPI LoadCursorIconHandler16( HGLOBAL16 hResource, HMODULE16 hModule, HRSRC16 hRsrc )
1677 FIXME_(cursor)("(%04x,%04x,%04x): old 2.x resources are not supported!\n",
1678 hResource, hModule, hRsrc);
1679 return (HGLOBAL16)0;
1682 /**********************************************************************
1683 * LoadDIBIconHandler (USER.357)
1685 * RT_ICON resource loader, installed by USER_SignalProc when module
1686 * is initialized.
1688 HGLOBAL16 WINAPI LoadDIBIconHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1690 /* If hResource is zero we must allocate a new memory block, if it's
1691 * non-zero but GlobalLock() returns NULL then it was discarded and
1692 * we have to recommit some memory, otherwise we just need to check
1693 * the block size. See LoadProc() in 16-bit SDK for more.
1696 hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1697 if( hMemObj )
1699 LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1700 hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1701 SizeofResource16(hModule, hRsrc), TRUE, 0x00030000,
1702 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR );
1704 return hMemObj;
1707 /**********************************************************************
1708 * LoadDIBCursorHandler (USER.356)
1710 * RT_CURSOR resource loader. Same as above.
1712 HGLOBAL16 WINAPI LoadDIBCursorHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1714 hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1715 if( hMemObj )
1717 LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1718 hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1719 SizeofResource16(hModule, hRsrc), FALSE, 0x00030000,
1720 GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1722 return hMemObj;
1725 /**********************************************************************
1726 * LoadIconHandler (USER.456)
1728 HICON16 WINAPI LoadIconHandler16( HGLOBAL16 hResource, BOOL16 bNew )
1730 LPBYTE bits = (LPBYTE)LockResource16( hResource );
1732 TRACE_(cursor)("hRes=%04x\n",hResource);
1734 return CURSORICON_CreateFromResource( 0, 0, bits, 0, TRUE,
1735 bNew ? 0x00030000 : 0x00020000, 0, 0, LR_DEFAULTCOLOR );
1738 /***********************************************************************
1739 * LoadCursorW (USER32.@)
1741 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
1743 return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0,
1744 LR_SHARED | LR_DEFAULTSIZE );
1747 /***********************************************************************
1748 * LoadCursorA (USER32.@)
1750 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
1752 return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0,
1753 LR_SHARED | LR_DEFAULTSIZE );
1756 /***********************************************************************
1757 * LoadCursorFromFileW (USER32.@)
1759 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
1761 return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0,
1762 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1765 /***********************************************************************
1766 * LoadCursorFromFileA (USER32.@)
1768 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
1770 return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0,
1771 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1774 /***********************************************************************
1775 * LoadIconW (USER32.@)
1777 HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
1779 return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0,
1780 LR_SHARED | LR_DEFAULTSIZE );
1783 /***********************************************************************
1784 * LoadIconA (USER32.@)
1786 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
1788 return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0,
1789 LR_SHARED | LR_DEFAULTSIZE );
1792 /**********************************************************************
1793 * GetIconInfo (USER.395)
1795 BOOL16 WINAPI GetIconInfo16(HICON16 hIcon,LPICONINFO16 iconinfo)
1797 ICONINFO ii32;
1798 BOOL16 ret = GetIconInfo((HICON)hIcon, &ii32);
1800 iconinfo->fIcon = ii32.fIcon;
1801 iconinfo->xHotspot = ii32.xHotspot;
1802 iconinfo->yHotspot = ii32.yHotspot;
1803 iconinfo->hbmMask = ii32.hbmMask;
1804 iconinfo->hbmColor = ii32.hbmColor;
1805 return ret;
1808 /**********************************************************************
1809 * GetIconInfo (USER32.@)
1811 BOOL WINAPI GetIconInfo(HICON hIcon,PICONINFO iconinfo) {
1812 CURSORICONINFO *ciconinfo;
1814 ciconinfo = GlobalLock16(hIcon);
1815 if (!ciconinfo)
1816 return FALSE;
1818 if ( (ciconinfo->ptHotSpot.x == ICON_HOTSPOT) &&
1819 (ciconinfo->ptHotSpot.y == ICON_HOTSPOT) )
1821 iconinfo->fIcon = TRUE;
1822 iconinfo->xHotspot = ciconinfo->nWidth / 2;
1823 iconinfo->yHotspot = ciconinfo->nHeight / 2;
1825 else
1827 iconinfo->fIcon = FALSE;
1828 iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
1829 iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
1832 iconinfo->hbmColor = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1833 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
1834 (char *)(ciconinfo + 1)
1835 + ciconinfo->nHeight *
1836 BITMAP_GetWidthBytes (ciconinfo->nWidth,1) );
1837 iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1838 1, 1, (char *)(ciconinfo + 1));
1840 GlobalUnlock16(hIcon);
1842 return TRUE;
1845 /**********************************************************************
1846 * CreateIconIndirect (USER32.@)
1848 HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
1850 BITMAP bmpXor,bmpAnd;
1851 HICON hObj;
1852 int sizeXor,sizeAnd;
1854 GetObjectA( iconinfo->hbmColor, sizeof(bmpXor), &bmpXor );
1855 GetObjectA( iconinfo->hbmMask, sizeof(bmpAnd), &bmpAnd );
1857 sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
1858 sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
1860 hObj = GlobalAlloc16( GMEM_MOVEABLE,
1861 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
1862 if (hObj)
1864 CURSORICONINFO *info;
1866 info = (CURSORICONINFO *)GlobalLock16( hObj );
1868 /* If we are creating an icon, the hotspot is unused */
1869 if (iconinfo->fIcon)
1871 info->ptHotSpot.x = ICON_HOTSPOT;
1872 info->ptHotSpot.y = ICON_HOTSPOT;
1874 else
1876 info->ptHotSpot.x = iconinfo->xHotspot;
1877 info->ptHotSpot.y = iconinfo->yHotspot;
1880 info->nWidth = bmpXor.bmWidth;
1881 info->nHeight = bmpXor.bmHeight;
1882 info->nWidthBytes = bmpXor.bmWidthBytes;
1883 info->bPlanes = bmpXor.bmPlanes;
1884 info->bBitsPerPixel = bmpXor.bmBitsPixel;
1886 /* Transfer the bitmap bits to the CURSORICONINFO structure */
1888 GetBitmapBits( iconinfo->hbmMask ,sizeAnd,(char*)(info + 1) );
1889 GetBitmapBits( iconinfo->hbmColor,sizeXor,(char*)(info + 1) +sizeAnd);
1890 GlobalUnlock16( hObj );
1892 return hObj;
1896 /**********************************************************************
1897 * DrawIconEx (USER.394)
1899 BOOL16 WINAPI DrawIconEx16 (HDC16 hdc, INT16 xLeft, INT16 yTop, HICON16 hIcon,
1900 INT16 cxWidth, INT16 cyWidth, UINT16 istep,
1901 HBRUSH16 hbr, UINT16 flags)
1903 return DrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
1904 istep, hbr, flags);
1908 /******************************************************************************
1909 * DrawIconEx (USER32.@) Draws an icon or cursor on device context
1911 * NOTES
1912 * Why is this using SM_CXICON instead of SM_CXCURSOR?
1914 * PARAMS
1915 * hdc [I] Handle to device context
1916 * x0 [I] X coordinate of upper left corner
1917 * y0 [I] Y coordinate of upper left corner
1918 * hIcon [I] Handle to icon to draw
1919 * cxWidth [I] Width of icon
1920 * cyWidth [I] Height of icon
1921 * istep [I] Index of frame in animated cursor
1922 * hbr [I] Handle to background brush
1923 * flags [I] Icon-drawing flags
1925 * RETURNS
1926 * Success: TRUE
1927 * Failure: FALSE
1929 BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
1930 INT cxWidth, INT cyWidth, UINT istep,
1931 HBRUSH hbr, UINT flags )
1933 CURSORICONINFO *ptr = (CURSORICONINFO *)GlobalLock16 (hIcon);
1934 HDC hDC_off = 0, hMemDC = CreateCompatibleDC (hdc);
1935 BOOL result = FALSE, DoOffscreen;
1936 HBITMAP hB_off = 0, hOld = 0;
1938 if (!ptr) return FALSE;
1939 TRACE_(icon)("(hdc=%x,pos=%d.%d,hicon=%x,extend=%d.%d,istep=%d,br=%x,flags=0x%08x)\n",
1940 hdc,x0,y0,hIcon,cxWidth,cyWidth,istep,hbr,flags
1943 if (istep)
1944 FIXME_(icon)("Ignoring istep=%d\n", istep);
1945 if (flags & DI_COMPAT)
1946 FIXME_(icon)("Ignoring flag DI_COMPAT\n");
1948 if (!flags) {
1949 FIXME_(icon)("no flags set? setting to DI_NORMAL\n");
1950 flags = DI_NORMAL;
1953 /* Calculate the size of the destination image. */
1954 if (cxWidth == 0)
1956 if (flags & DI_DEFAULTSIZE)
1957 cxWidth = GetSystemMetrics (SM_CXICON);
1958 else
1959 cxWidth = ptr->nWidth;
1961 if (cyWidth == 0)
1963 if (flags & DI_DEFAULTSIZE)
1964 cyWidth = GetSystemMetrics (SM_CYICON);
1965 else
1966 cyWidth = ptr->nHeight;
1969 DoOffscreen = (GetObjectType( hbr ) == OBJ_BRUSH);
1971 if (DoOffscreen) {
1972 RECT r;
1974 r.left = 0;
1975 r.top = 0;
1976 r.right = cxWidth;
1977 r.bottom = cxWidth;
1979 hDC_off = CreateCompatibleDC(hdc);
1980 hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth);
1981 if (hDC_off && hB_off) {
1982 hOld = SelectObject(hDC_off, hB_off);
1983 FillRect(hDC_off, &r, hbr);
1987 if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
1989 HBITMAP hXorBits, hAndBits;
1990 COLORREF oldFg, oldBg;
1991 INT nStretchMode;
1993 nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
1995 hXorBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1996 ptr->bPlanes, ptr->bBitsPerPixel,
1997 (char *)(ptr + 1)
1998 + ptr->nHeight *
1999 BITMAP_GetWidthBytes(ptr->nWidth,1) );
2000 hAndBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
2001 1, 1, (char *)(ptr+1) );
2002 oldFg = SetTextColor( hdc, RGB(0,0,0) );
2003 oldBg = SetBkColor( hdc, RGB(255,255,255) );
2005 if (hXorBits && hAndBits)
2007 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
2008 if (flags & DI_MASK)
2010 if (DoOffscreen)
2011 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
2012 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
2013 else
2014 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
2015 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
2017 SelectObject( hMemDC, hXorBits );
2018 if (flags & DI_IMAGE)
2020 if (DoOffscreen)
2021 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
2022 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
2023 else
2024 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
2025 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
2027 SelectObject( hMemDC, hBitTemp );
2028 result = TRUE;
2031 SetTextColor( hdc, oldFg );
2032 SetBkColor( hdc, oldBg );
2033 if (hXorBits) DeleteObject( hXorBits );
2034 if (hAndBits) DeleteObject( hAndBits );
2035 SetStretchBltMode (hdc, nStretchMode);
2036 if (DoOffscreen) {
2037 BitBlt(hdc, x0, y0, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
2038 SelectObject(hDC_off, hOld);
2041 if (hMemDC) DeleteDC( hMemDC );
2042 if (hDC_off) DeleteDC(hDC_off);
2043 if (hB_off) DeleteObject(hB_off);
2044 GlobalUnlock16( hIcon );
2045 return result;
2048 /***********************************************************************
2049 * DIB_FixColorsToLoadflags
2051 * Change color table entries when LR_LOADTRANSPARENT or LR_LOADMAP3DCOLORS
2052 * are in loadflags
2054 static void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags, BYTE pix)
2056 int colors;
2057 COLORREF c_W, c_S, c_F, c_L, c_C;
2058 int incr,i;
2059 RGBQUAD *ptr;
2061 if (bmi->bmiHeader.biBitCount > 8) return;
2062 if (bmi->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)) incr = 4;
2063 else if (bmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) incr = 3;
2064 else {
2065 WARN_(resource)("Wrong bitmap header size!\n");
2066 return;
2068 colors = bmi->bmiHeader.biClrUsed;
2069 if (!colors && (bmi->bmiHeader.biBitCount <= 8))
2070 colors = 1 << bmi->bmiHeader.biBitCount;
2071 c_W = GetSysColor(COLOR_WINDOW);
2072 c_S = GetSysColor(COLOR_3DSHADOW);
2073 c_F = GetSysColor(COLOR_3DFACE);
2074 c_L = GetSysColor(COLOR_3DLIGHT);
2075 if (loadflags & LR_LOADTRANSPARENT) {
2076 switch (bmi->bmiHeader.biBitCount) {
2077 case 1: pix = pix >> 7; break;
2078 case 4: pix = pix >> 4; break;
2079 case 8: break;
2080 default:
2081 WARN_(resource)("(%d): Unsupported depth\n", bmi->bmiHeader.biBitCount);
2082 return;
2084 if (pix >= colors) {
2085 WARN_(resource)("pixel has color index greater than biClrUsed!\n");
2086 return;
2088 if (loadflags & LR_LOADMAP3DCOLORS) c_W = c_F;
2089 ptr = (RGBQUAD*)((char*)bmi->bmiColors+pix*incr);
2090 ptr->rgbBlue = GetBValue(c_W);
2091 ptr->rgbGreen = GetGValue(c_W);
2092 ptr->rgbRed = GetRValue(c_W);
2094 if (loadflags & LR_LOADMAP3DCOLORS)
2095 for (i=0; i<colors; i++) {
2096 ptr = (RGBQUAD*)((char*)bmi->bmiColors+i*incr);
2097 c_C = RGB(ptr->rgbRed, ptr->rgbGreen, ptr->rgbBlue);
2098 if (c_C == RGB(128, 128, 128)) {
2099 ptr->rgbRed = GetRValue(c_S);
2100 ptr->rgbGreen = GetGValue(c_S);
2101 ptr->rgbBlue = GetBValue(c_S);
2102 } else if (c_C == RGB(192, 192, 192)) {
2103 ptr->rgbRed = GetRValue(c_F);
2104 ptr->rgbGreen = GetGValue(c_F);
2105 ptr->rgbBlue = GetBValue(c_F);
2106 } else if (c_C == RGB(223, 223, 223)) {
2107 ptr->rgbRed = GetRValue(c_L);
2108 ptr->rgbGreen = GetGValue(c_L);
2109 ptr->rgbBlue = GetBValue(c_L);
2115 /**********************************************************************
2116 * BITMAP_Load
2118 static HBITMAP BITMAP_Load( HINSTANCE instance,LPCWSTR name, UINT loadflags )
2120 HBITMAP hbitmap = 0;
2121 HRSRC hRsrc;
2122 HGLOBAL handle;
2123 char *ptr = NULL;
2124 BITMAPINFO *info, *fix_info=NULL;
2125 HGLOBAL hFix;
2126 int size;
2128 if (!(loadflags & LR_LOADFROMFILE))
2130 if (!instance)
2132 /* OEM bitmap: try to load the resource from user32.dll */
2133 if (HIWORD(name)) return 0;
2134 if (!(instance = GetModuleHandleA("user32.dll"))) return 0;
2136 if (!(hRsrc = FindResourceW( instance, name, RT_BITMAPW ))) return 0;
2137 if (!(handle = LoadResource( instance, hRsrc ))) return 0;
2139 if ((info = (BITMAPINFO *)LockResource( handle )) == NULL) return 0;
2141 else
2143 if (!(ptr = map_fileW( name ))) return 0;
2144 info = (BITMAPINFO *)(ptr + sizeof(BITMAPFILEHEADER));
2146 size = DIB_BitmapInfoSize(info, DIB_RGB_COLORS);
2147 if ((hFix = GlobalAlloc(0, size))) fix_info=GlobalLock(hFix);
2148 if (fix_info) {
2149 BYTE pix;
2151 memcpy(fix_info, info, size);
2152 pix = *((LPBYTE)info+DIB_BitmapInfoSize(info, DIB_RGB_COLORS));
2153 DIB_FixColorsToLoadflags(fix_info, loadflags, pix);
2154 if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
2155 if (screen_dc)
2157 char *bits = (char *)info + size;
2158 if (loadflags & LR_CREATEDIBSECTION) {
2159 DIBSECTION dib;
2160 hbitmap = CreateDIBSection(screen_dc, fix_info, DIB_RGB_COLORS, NULL, 0, 0);
2161 GetObjectA(hbitmap, sizeof(DIBSECTION), &dib);
2162 SetDIBits(screen_dc, hbitmap, 0, dib.dsBm.bmHeight, bits, info,
2163 DIB_RGB_COLORS);
2165 else {
2166 hbitmap = CreateDIBitmap( screen_dc, &fix_info->bmiHeader, CBM_INIT,
2167 bits, fix_info, DIB_RGB_COLORS );
2170 GlobalUnlock(hFix);
2171 GlobalFree(hFix);
2173 if (loadflags & LR_LOADFROMFILE) UnmapViewOfFile( ptr );
2174 return hbitmap;
2178 /***********************************************************************
2179 * LoadImage (USER.389)
2182 HANDLE16 WINAPI LoadImage16( HINSTANCE16 hinst, LPCSTR name, UINT16 type,
2183 INT16 desiredx, INT16 desiredy, UINT16 loadflags)
2185 return LoadImageA( hinst, name, type, desiredx, desiredy, loadflags );
2188 /**********************************************************************
2189 * LoadImageA (USER32.@)
2191 * FIXME: implementation lacks some features, see LR_ defines in winuser.h
2194 /* filter for page-fault exceptions */
2195 static WINE_EXCEPTION_FILTER(page_fault)
2197 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
2198 return EXCEPTION_EXECUTE_HANDLER;
2199 return EXCEPTION_CONTINUE_SEARCH;
2202 /*********************************************************************/
2204 HANDLE WINAPI LoadImageA( HINSTANCE hinst, LPCSTR name, UINT type,
2205 INT desiredx, INT desiredy, UINT loadflags)
2207 HANDLE res;
2208 LPWSTR u_name;
2210 if (!HIWORD(name))
2211 return LoadImageW(hinst, (LPWSTR)name, type, desiredx, desiredy, loadflags);
2213 __TRY {
2214 DWORD len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
2215 u_name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2216 MultiByteToWideChar( CP_ACP, 0, name, -1, u_name, len );
2218 __EXCEPT(page_fault) {
2219 SetLastError( ERROR_INVALID_PARAMETER );
2220 return 0;
2222 __ENDTRY
2223 res = LoadImageW(hinst, u_name, type, desiredx, desiredy, loadflags);
2224 HeapFree(GetProcessHeap(), 0, u_name);
2225 return res;
2229 /******************************************************************************
2230 * LoadImageW (USER32.@) Loads an icon, cursor, or bitmap
2232 * PARAMS
2233 * hinst [I] Handle of instance that contains image
2234 * name [I] Name of image
2235 * type [I] Type of image
2236 * desiredx [I] Desired width
2237 * desiredy [I] Desired height
2238 * loadflags [I] Load flags
2240 * RETURNS
2241 * Success: Handle to newly loaded image
2242 * Failure: NULL
2244 * FIXME: Implementation lacks some features, see LR_ defines in winuser.h
2246 HANDLE WINAPI LoadImageW( HINSTANCE hinst, LPCWSTR name, UINT type,
2247 INT desiredx, INT desiredy, UINT loadflags )
2249 if (HIWORD(name)) {
2250 TRACE_(resource)("(0x%04x,%p,%d,%d,%d,0x%08x)\n",
2251 hinst,name,type,desiredx,desiredy,loadflags);
2252 } else {
2253 TRACE_(resource)("(0x%04x,%p,%d,%d,%d,0x%08x)\n",
2254 hinst,name,type,desiredx,desiredy,loadflags);
2256 if (loadflags & LR_DEFAULTSIZE) {
2257 if (type == IMAGE_ICON) {
2258 if (!desiredx) desiredx = GetSystemMetrics(SM_CXICON);
2259 if (!desiredy) desiredy = GetSystemMetrics(SM_CYICON);
2260 } else if (type == IMAGE_CURSOR) {
2261 if (!desiredx) desiredx = GetSystemMetrics(SM_CXCURSOR);
2262 if (!desiredy) desiredy = GetSystemMetrics(SM_CYCURSOR);
2265 if (loadflags & LR_LOADFROMFILE) loadflags &= ~LR_SHARED;
2266 switch (type) {
2267 case IMAGE_BITMAP:
2268 return BITMAP_Load( hinst, name, loadflags );
2270 case IMAGE_ICON:
2271 if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
2272 if (screen_dc)
2274 UINT palEnts = GetSystemPaletteEntries(screen_dc, 0, 0, NULL);
2275 if (palEnts == 0) palEnts = 256;
2276 return CURSORICON_Load(hinst, name, desiredx, desiredy,
2277 palEnts, FALSE, loadflags);
2279 break;
2281 case IMAGE_CURSOR:
2282 return CURSORICON_Load(hinst, name, desiredx, desiredy,
2283 1, TRUE, loadflags);
2285 return 0;
2289 /******************************************************************************
2290 * CopyImage (USER.390) Creates new image and copies attributes to it
2293 HICON16 WINAPI CopyImage16( HANDLE16 hnd, UINT16 type, INT16 desiredx,
2294 INT16 desiredy, UINT16 flags )
2296 return (HICON16)CopyImage((HANDLE)hnd, (UINT)type, (INT)desiredx,
2297 (INT)desiredy, (UINT)flags);
2300 /******************************************************************************
2301 * CopyImage (USER32.@) Creates new image and copies attributes to it
2303 * PARAMS
2304 * hnd [I] Handle to image to copy
2305 * type [I] Type of image to copy
2306 * desiredx [I] Desired width of new image
2307 * desiredy [I] Desired height of new image
2308 * flags [I] Copy flags
2310 * RETURNS
2311 * Success: Handle to newly created image
2312 * Failure: NULL
2314 * FIXME: implementation still lacks nearly all features, see LR_*
2315 * defines in winuser.h
2317 HICON WINAPI CopyImage( HANDLE hnd, UINT type, INT desiredx,
2318 INT desiredy, UINT flags )
2320 switch (type)
2322 case IMAGE_BITMAP:
2323 return BITMAP_CopyBitmap(hnd);
2324 case IMAGE_ICON:
2325 return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags);
2326 case IMAGE_CURSOR:
2327 /* Should call CURSORICON_ExtCopy but more testing
2328 * needs to be done before we change this
2330 return CopyCursor(hnd);
2332 return 0;
2336 /******************************************************************************
2337 * LoadBitmapW (USER32.@) Loads bitmap from the executable file
2339 * RETURNS
2340 * Success: Handle to specified bitmap
2341 * Failure: NULL
2343 HBITMAP WINAPI LoadBitmapW(
2344 HINSTANCE instance, /* [in] Handle to application instance */
2345 LPCWSTR name) /* [in] Address of bitmap resource name */
2347 return LoadImageW( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2350 /**********************************************************************
2351 * LoadBitmapA (USER32.@)
2353 HBITMAP WINAPI LoadBitmapA( HINSTANCE instance, LPCSTR name )
2355 return LoadImageA( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2358 /**********************************************************************
2359 * LoadBitmap (USER.175)
2361 HBITMAP16 WINAPI LoadBitmap16( HINSTANCE16 instance, LPCSTR name )
2363 return LoadBitmapA( instance, name );