Release 20010216.
[wine/multimedia.git] / windows / cursoricon.c
blob19f5d19886f5cb40bb4e42f90c584d045ad9978b
1 /*
2 * Cursor and icon support
4 * Copyright 1995 Alexandre Julliard
5 * 1996 Martin Von Loewis
6 * 1997 Alex Korobka
7 * 1998 Turchanov Sergey
8 */
11 * Theory:
13 * http://www.microsoft.com/win32dev/ui/icons.htm
15 * Cursors and icons are stored in a global heap block, with the
16 * following layout:
18 * CURSORICONINFO info;
19 * BYTE[] ANDbits;
20 * BYTE[] XORbits;
22 * The bits structures are in the format of a device-dependent bitmap.
24 * This layout is very sub-optimal, as the bitmap bits are stored in
25 * the X client instead of in the server like other bitmaps; however,
26 * some programs (notably Paint Brush) expect to be able to manipulate
27 * the bits directly :-(
29 * FIXME: what are we going to do with animation and color (bpp > 1) cursors ?!
32 #include <string.h>
33 #include <stdlib.h>
35 #include "windef.h"
36 #include "wingdi.h"
37 #include "wine/winbase16.h"
38 #include "wine/winuser16.h"
39 #include "heap.h"
40 #include "palette.h"
41 #include "bitmap.h"
42 #include "cursoricon.h"
43 #include "module.h"
44 #include "debugtools.h"
45 #include "user.h"
46 #include "input.h"
47 #include "message.h"
48 #include "winerror.h"
50 DECLARE_DEBUG_CHANNEL(cursor);
51 DECLARE_DEBUG_CHANNEL(icon);
52 DECLARE_DEBUG_CHANNEL(resource);
54 static HCURSOR hActiveCursor = 0; /* Active cursor */
55 static INT CURSOR_ShowCount = 0; /* Cursor display count */
56 static RECT CURSOR_ClipRect; /* Cursor clipping rect */
58 static HDC screen_dc;
60 /**********************************************************************
61 * ICONCACHE for cursors/icons loaded with LR_SHARED.
63 * FIXME: This should not be allocated on the system heap, but on a
64 * subsystem-global heap (i.e. one for all Win16 processes,
65 * and one for each Win32 process).
67 typedef struct tagICONCACHE
69 struct tagICONCACHE *next;
71 HMODULE hModule;
72 HRSRC hRsrc;
73 HRSRC hGroupRsrc;
74 HANDLE handle;
76 INT count;
78 } ICONCACHE;
80 static ICONCACHE *IconAnchor = NULL;
81 static CRITICAL_SECTION IconCrst = CRITICAL_SECTION_INIT;
82 static WORD ICON_HOTSPOT = 0x4242;
85 /***********************************************************************
86 * map_fileW
88 * Helper function to map a file to memory:
89 * name - file name
90 * [RETURN] ptr - pointer to mapped file
92 static void *map_fileW( LPCWSTR name )
94 HANDLE hFile, hMapping;
95 LPVOID ptr = NULL;
97 hFile = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL,
98 OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0 );
99 if (hFile != INVALID_HANDLE_VALUE)
101 hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
102 CloseHandle( hFile );
103 if (hMapping)
105 ptr = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
106 CloseHandle( hMapping );
109 return ptr;
113 /**********************************************************************
114 * CURSORICON_FindSharedIcon
116 static HANDLE CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
118 HANDLE handle = 0;
119 ICONCACHE *ptr;
121 EnterCriticalSection( &IconCrst );
123 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
124 if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
126 ptr->count++;
127 handle = ptr->handle;
128 break;
131 LeaveCriticalSection( &IconCrst );
133 return handle;
136 /*************************************************************************
137 * CURSORICON_FindCache
139 * Given a handle, find the corresponding cache element
141 * PARAMS
142 * Handle [I] handle to an Image
144 * RETURNS
145 * Success: The cache entry
146 * Failure: NULL
149 static ICONCACHE* CURSORICON_FindCache(HANDLE handle)
151 ICONCACHE *ptr;
152 ICONCACHE *pRet=NULL;
153 BOOL IsFound = FALSE;
154 int count;
156 EnterCriticalSection( &IconCrst );
158 for (count = 0, ptr = IconAnchor; ptr != NULL && !IsFound; ptr = ptr->next, count++ )
160 if ( handle == ptr->handle )
162 IsFound = TRUE;
163 pRet = ptr;
167 LeaveCriticalSection( &IconCrst );
169 return pRet;
172 /**********************************************************************
173 * CURSORICON_AddSharedIcon
175 static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HRSRC hGroupRsrc, HANDLE handle )
177 ICONCACHE *ptr = HeapAlloc( SystemHeap, 0, sizeof(ICONCACHE) );
178 if ( !ptr ) return;
180 ptr->hModule = hModule;
181 ptr->hRsrc = hRsrc;
182 ptr->handle = handle;
183 ptr->hGroupRsrc = hGroupRsrc;
184 ptr->count = 1;
186 EnterCriticalSection( &IconCrst );
187 ptr->next = IconAnchor;
188 IconAnchor = ptr;
189 LeaveCriticalSection( &IconCrst );
192 /**********************************************************************
193 * CURSORICON_DelSharedIcon
195 static INT CURSORICON_DelSharedIcon( HANDLE handle )
197 INT count = -1;
198 ICONCACHE *ptr;
200 EnterCriticalSection( &IconCrst );
202 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
203 if ( ptr->handle == handle )
205 if ( ptr->count > 0 ) ptr->count--;
206 count = ptr->count;
207 break;
210 LeaveCriticalSection( &IconCrst );
212 return count;
215 /**********************************************************************
216 * CURSORICON_FreeModuleIcons
218 void CURSORICON_FreeModuleIcons( HMODULE hModule )
220 ICONCACHE **ptr = &IconAnchor;
222 if ( HIWORD( hModule ) )
223 hModule = MapHModuleLS( hModule );
224 else
225 hModule = GetExePtr( hModule );
227 EnterCriticalSection( &IconCrst );
229 while ( *ptr )
231 if ( (*ptr)->hModule == hModule )
233 ICONCACHE *freePtr = *ptr;
234 *ptr = freePtr->next;
236 GlobalFree16( freePtr->handle );
237 HeapFree( SystemHeap, 0, freePtr );
238 continue;
240 ptr = &(*ptr)->next;
243 LeaveCriticalSection( &IconCrst );
246 /**********************************************************************
247 * CURSORICON_FindBestIcon
249 * Find the icon closest to the requested size and number of colors.
251 static CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
252 int height, int colors )
254 int i;
255 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
256 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
257 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
259 if (dir->idCount < 1)
261 WARN_(icon)("Empty directory!\n" );
262 return NULL;
264 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
266 /* Find Best Fit */
267 iTotalDiff = 0xFFFFFFFF;
268 iColorDiff = 0xFFFFFFFF;
269 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
271 iTempXDiff = abs(width - entry->ResInfo.icon.bWidth);
272 iTempYDiff = abs(height - entry->ResInfo.icon.bHeight);
274 if(iTotalDiff > (iTempXDiff + iTempYDiff))
276 iXDiff = iTempXDiff;
277 iYDiff = iTempYDiff;
278 iTotalDiff = iXDiff + iYDiff;
282 /* Find Best Colors for Best Fit */
283 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
285 if(abs(width - entry->ResInfo.icon.bWidth) == iXDiff &&
286 abs(height - entry->ResInfo.icon.bHeight) == iYDiff)
288 iTempColorDiff = abs(colors - entry->ResInfo.icon.bColorCount);
289 if(iColorDiff > iTempColorDiff)
291 bestEntry = entry;
292 iColorDiff = iTempColorDiff;
297 return bestEntry;
301 /**********************************************************************
302 * CURSORICON_FindBestCursor
304 * Find the cursor closest to the requested size.
305 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
306 * ignored too
308 static CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
309 int width, int height, int color)
311 int i, maxwidth, maxheight;
312 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
314 if (dir->idCount < 1)
316 WARN_(cursor)("Empty directory!\n" );
317 return NULL;
319 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
321 /* Double height to account for AND and XOR masks */
323 height *= 2;
325 /* First find the largest one smaller than or equal to the requested size*/
327 maxwidth = maxheight = 0;
328 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
329 if ((entry->ResInfo.cursor.wWidth <= width) && (entry->ResInfo.cursor.wHeight <= height) &&
330 (entry->ResInfo.cursor.wWidth > maxwidth) && (entry->ResInfo.cursor.wHeight > maxheight) &&
331 (entry->wBitCount == 1))
333 bestEntry = entry;
334 maxwidth = entry->ResInfo.cursor.wWidth;
335 maxheight = entry->ResInfo.cursor.wHeight;
337 if (bestEntry) return bestEntry;
339 /* Now find the smallest one larger than the requested size */
341 maxwidth = maxheight = 255;
342 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
343 if ((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;
351 return bestEntry;
354 /*********************************************************************
355 * The main purpose of this function is to create fake resource directory
356 * and fake resource entries. There are several reasons for this:
357 * - CURSORICONDIR and CURSORICONFILEDIR differ in sizes and their
358 * fields
359 * There are some "bad" cursor files which do not have
360 * bColorCount initialized but instead one must read this info
361 * directly from corresponding DIB sections
362 * Note: wResId is index to array of pointer returned in ptrs (origin is 1)
364 BOOL CURSORICON_SimulateLoadingFromResourceW( LPWSTR filename, BOOL fCursor,
365 CURSORICONDIR **res, LPBYTE **ptr)
367 LPBYTE _free;
368 CURSORICONFILEDIR *bits;
369 int entries, size, i;
371 *res = NULL;
372 *ptr = NULL;
373 if (!(bits = map_fileW( filename ))) return FALSE;
375 /* FIXME: test for inimated icons
376 * hack to load the first icon from the *.ani file
378 if ( *(LPDWORD)bits==0x46464952 ) /* "RIFF" */
379 { LPBYTE pos = (LPBYTE) bits;
380 FIXME_(cursor)("Animated icons not correctly implemented! %p \n", bits);
382 for (;;)
383 { if (*(LPDWORD)pos==0x6e6f6369) /* "icon" */
384 { FIXME_(cursor)("icon entry found! %p\n", bits);
385 pos+=4;
386 if ( !*(LPWORD) pos==0x2fe) /* iconsize */
387 { goto fail;
389 bits=(CURSORICONFILEDIR*)(pos+4);
390 FIXME_(cursor)("icon size ok. offset=%p \n", bits);
391 break;
393 pos+=2;
394 if (pos>=(LPBYTE)bits+766) goto fail;
397 if (!(entries = bits->idCount)) goto fail;
398 size = sizeof(CURSORICONDIR) + sizeof(CURSORICONDIRENTRY) * (entries - 1);
399 _free = (LPBYTE) size;
401 for (i=0; i < entries; i++)
402 size += bits->idEntries[i].dwDIBSize + (fCursor ? sizeof(POINT16): 0);
404 if (!(*ptr = HeapAlloc( GetProcessHeap(), 0,
405 entries * sizeof (CURSORICONDIRENTRY*)))) goto fail;
406 if (!(*res = HeapAlloc( GetProcessHeap(), 0, size))) goto fail;
408 _free = (LPBYTE)(*res) + (int)_free;
409 memcpy((*res), bits, 6);
410 for (i=0; i<entries; i++)
412 ((LPBYTE*)(*ptr))[i] = _free;
413 if (fCursor) {
414 (*res)->idEntries[i].ResInfo.cursor.wWidth=bits->idEntries[i].bWidth;
415 (*res)->idEntries[i].ResInfo.cursor.wHeight=bits->idEntries[i].bHeight;
416 ((LPPOINT16)_free)->x=bits->idEntries[i].xHotspot;
417 ((LPPOINT16)_free)->y=bits->idEntries[i].yHotspot;
418 _free+=sizeof(POINT16);
419 } else {
420 (*res)->idEntries[i].ResInfo.icon.bWidth=bits->idEntries[i].bWidth;
421 (*res)->idEntries[i].ResInfo.icon.bHeight=bits->idEntries[i].bHeight;
422 (*res)->idEntries[i].ResInfo.icon.bColorCount = bits->idEntries[i].bColorCount;
424 (*res)->idEntries[i].wPlanes=1;
425 (*res)->idEntries[i].wBitCount = ((LPBITMAPINFOHEADER)((LPBYTE)bits +
426 bits->idEntries[i].dwDIBOffset))->biBitCount;
427 (*res)->idEntries[i].dwBytesInRes = bits->idEntries[i].dwDIBSize;
428 (*res)->idEntries[i].wResId=i+1;
430 memcpy(_free,(LPBYTE)bits +bits->idEntries[i].dwDIBOffset,
431 (*res)->idEntries[i].dwBytesInRes);
432 _free += (*res)->idEntries[i].dwBytesInRes;
434 UnmapViewOfFile( bits );
435 return TRUE;
436 fail:
437 if (*res) HeapFree( GetProcessHeap(), 0, *res );
438 if (*ptr) HeapFree( GetProcessHeap(), 0, *ptr );
439 UnmapViewOfFile( bits );
440 return FALSE;
444 /**********************************************************************
445 * CURSORICON_CreateFromResource
447 * Create a cursor or icon from in-memory resource template.
449 * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
450 * with cbSize parameter as well.
452 static HGLOBAL16 CURSORICON_CreateFromResource( HINSTANCE16 hInstance, HGLOBAL16 hObj, LPBYTE bits,
453 UINT cbSize, BOOL bIcon, DWORD dwVersion,
454 INT width, INT height, UINT loadflags )
456 static HDC hdcMem;
457 int sizeAnd, sizeXor;
458 HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
459 BITMAP bmpXor, bmpAnd;
460 POINT16 hotspot;
461 BITMAPINFO *bmi;
462 BOOL DoStretch;
463 INT size;
465 hotspot.x = ICON_HOTSPOT;
466 hotspot.y = ICON_HOTSPOT;
468 TRACE_(cursor)("%08x (%u bytes), ver %08x, %ix%i %s %s\n",
469 (unsigned)bits, cbSize, (unsigned)dwVersion, width, height,
470 bIcon ? "icon" : "cursor", (loadflags & LR_MONOCHROME) ? "mono" : "" );
471 if (dwVersion == 0x00020000)
473 FIXME_(cursor)("\t2.xx resources are not supported\n");
474 return 0;
477 if (bIcon)
478 bmi = (BITMAPINFO *)bits;
479 else /* get the hotspot */
481 POINT16 *pt = (POINT16 *)bits;
482 hotspot = *pt;
483 bmi = (BITMAPINFO *)(pt + 1);
485 size = DIB_BitmapInfoSize( bmi, DIB_RGB_COLORS );
487 if (!width) width = bmi->bmiHeader.biWidth;
488 if (!height) height = bmi->bmiHeader.biHeight/2;
489 DoStretch = (bmi->bmiHeader.biHeight/2 != height) ||
490 (bmi->bmiHeader.biWidth != width);
492 /* Check bitmap header */
494 if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
495 (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) ||
496 bmi->bmiHeader.biCompression != BI_RGB) )
498 WARN_(cursor)("\tinvalid resource bitmap header.\n");
499 return 0;
502 if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
503 if (screen_dc)
505 BITMAPINFO* pInfo;
507 /* Make sure we have room for the monochrome bitmap later on.
508 * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
509 * up to and including the biBitCount. In-memory icon resource
510 * format is as follows:
512 * BITMAPINFOHEADER icHeader // DIB header
513 * RGBQUAD icColors[] // Color table
514 * BYTE icXOR[] // DIB bits for XOR mask
515 * BYTE icAND[] // DIB bits for AND mask
518 if ((pInfo = (BITMAPINFO *)HeapAlloc( GetProcessHeap(), 0,
519 max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))))
521 memcpy( pInfo, bmi, size );
522 pInfo->bmiHeader.biHeight /= 2;
524 /* Create the XOR bitmap */
526 if (DoStretch) {
527 if(bIcon)
529 hXorBits = CreateCompatibleBitmap(screen_dc, width, height);
531 else
533 hXorBits = CreateBitmap(width, height, 1, 1, NULL);
535 if(hXorBits)
537 HBITMAP hOld;
538 BOOL res = FALSE;
540 if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
541 if (hdcMem) {
542 hOld = SelectObject(hdcMem, hXorBits);
543 res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
544 bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2,
545 (char*)bmi + size, pInfo, DIB_RGB_COLORS, SRCCOPY);
546 SelectObject(hdcMem, hOld);
548 if (!res) { DeleteObject(hXorBits); hXorBits = 0; }
550 } else hXorBits = CreateDIBitmap( screen_dc, &pInfo->bmiHeader,
551 CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS );
552 if( hXorBits )
554 char* xbits = (char *)bmi + size +
555 DIB_GetDIBImageBytes(bmi->bmiHeader.biWidth,
556 bmi->bmiHeader.biHeight,
557 bmi->bmiHeader.biBitCount) / 2;
559 pInfo->bmiHeader.biBitCount = 1;
560 if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
562 RGBQUAD *rgb = pInfo->bmiColors;
564 pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
565 rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
566 rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
567 rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
569 else
571 RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
573 rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
574 rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
577 /* Create the AND bitmap */
579 if (DoStretch) {
580 if ((hAndBits = CreateBitmap(width, height, 1, 1, NULL))) {
581 HBITMAP hOld;
582 BOOL res = FALSE;
584 if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
585 if (hdcMem) {
586 hOld = SelectObject(hdcMem, hAndBits);
587 res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
588 pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight,
589 xbits, pInfo, DIB_RGB_COLORS, SRCCOPY);
590 SelectObject(hdcMem, hOld);
592 if (!res) { DeleteObject(hAndBits); hAndBits = 0; }
594 } else hAndBits = CreateDIBitmap( screen_dc, &pInfo->bmiHeader,
595 CBM_INIT, xbits, pInfo, DIB_RGB_COLORS );
597 if( !hAndBits ) DeleteObject( hXorBits );
599 HeapFree( GetProcessHeap(), 0, pInfo );
603 if( !hXorBits || !hAndBits )
605 WARN_(cursor)("\tunable to create an icon bitmap.\n");
606 return 0;
609 /* Now create the CURSORICONINFO structure */
610 GetObjectA( hXorBits, sizeof(bmpXor), &bmpXor );
611 GetObjectA( hAndBits, sizeof(bmpAnd), &bmpAnd );
612 sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
613 sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
615 if (hObj) hObj = GlobalReAlloc16( hObj,
616 sizeof(CURSORICONINFO) + sizeXor + sizeAnd, GMEM_MOVEABLE );
617 if (!hObj) hObj = GlobalAlloc16( GMEM_MOVEABLE,
618 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
619 if (hObj)
621 CURSORICONINFO *info;
623 /* Make it owned by the module */
624 if (hInstance) hInstance = GetExePtr(hInstance);
625 FarSetOwner16( hObj, hInstance );
627 info = (CURSORICONINFO *)GlobalLock16( hObj );
628 info->ptHotSpot.x = hotspot.x;
629 info->ptHotSpot.y = hotspot.y;
630 info->nWidth = bmpXor.bmWidth;
631 info->nHeight = bmpXor.bmHeight;
632 info->nWidthBytes = bmpXor.bmWidthBytes;
633 info->bPlanes = bmpXor.bmPlanes;
634 info->bBitsPerPixel = bmpXor.bmBitsPixel;
636 /* Transfer the bitmap bits to the CURSORICONINFO structure */
638 GetBitmapBits( hAndBits, sizeAnd, (char *)(info + 1) );
639 GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
640 GlobalUnlock16( hObj );
643 DeleteObject( hAndBits );
644 DeleteObject( hXorBits );
645 return hObj;
649 /**********************************************************************
650 * CreateIconFromResourceEx (USER.450)
652 * FIXME: not sure about exact parameter types
654 HICON16 WINAPI CreateIconFromResourceEx16( LPBYTE bits, UINT16 cbSize, BOOL16 bIcon,
655 DWORD dwVersion, INT16 width, INT16 height, UINT16 cFlag )
657 return CreateIconFromResourceEx(bits, cbSize, bIcon, dwVersion,
658 width, height, cFlag);
662 /**********************************************************************
663 * CreateIconFromResource (USER32.@)
665 HICON WINAPI CreateIconFromResource( LPBYTE bits, UINT cbSize,
666 BOOL bIcon, DWORD dwVersion)
668 return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
672 /**********************************************************************
673 * CreateIconFromResourceEx (USER32.@)
675 HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
676 BOOL bIcon, DWORD dwVersion,
677 INT width, INT height,
678 UINT cFlag )
680 return CURSORICON_CreateFromResource( 0, 0, bits, cbSize, bIcon, dwVersion,
681 width, height, cFlag );
684 /**********************************************************************
685 * CURSORICON_Load
687 * Load a cursor or icon from resource or file.
689 HGLOBAL CURSORICON_Load( HINSTANCE hInstance, LPCWSTR name,
690 INT width, INT height, INT colors,
691 BOOL fCursor, UINT loadflags )
693 HANDLE handle = 0, h = 0;
694 HANDLE hRsrc;
695 CURSORICONDIR *dir;
696 CURSORICONDIRENTRY *dirEntry;
697 LPBYTE bits;
699 if ( loadflags & LR_LOADFROMFILE ) /* Load from file */
701 LPBYTE *ptr;
702 if (!CURSORICON_SimulateLoadingFromResourceW((LPWSTR)name, fCursor, &dir, &ptr))
703 return 0;
704 if (fCursor)
705 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(dir, width, height, 1);
706 else
707 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(dir, width, height, colors);
708 bits = ptr[dirEntry->wResId-1];
709 h = CURSORICON_CreateFromResource( 0, 0, bits, dirEntry->dwBytesInRes,
710 !fCursor, 0x00030000, width, height, loadflags);
711 HeapFree( GetProcessHeap(), 0, dir );
712 HeapFree( GetProcessHeap(), 0, ptr );
714 else /* Load from resource */
716 HANDLE hGroupRsrc;
717 WORD wResId;
718 DWORD dwBytesInRes;
720 if (!hInstance) /* Load OEM cursor/icon */
722 if (!(hInstance = GetModuleHandleA( "user32.dll" ))) return 0;
725 /* Normalize hInstance (must be uniquely represented for icon cache) */
727 if ( HIWORD( hInstance ) )
728 hInstance = MapHModuleLS( hInstance );
729 else
730 hInstance = GetExePtr( hInstance );
732 /* Get directory resource ID */
734 if (!(hRsrc = FindResourceW( hInstance, name,
735 fCursor ? RT_GROUP_CURSORW : RT_GROUP_ICONW )))
736 return 0;
737 hGroupRsrc = hRsrc;
739 /* Find the best entry in the directory */
741 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
742 if (!(dir = (CURSORICONDIR*)LockResource( handle ))) return 0;
743 if (fCursor)
744 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor( dir,
745 width, height, 1);
746 else
747 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon( dir,
748 width, height, colors );
749 if (!dirEntry) return 0;
750 wResId = dirEntry->wResId;
751 dwBytesInRes = dirEntry->dwBytesInRes;
752 FreeResource( handle );
754 /* Load the resource */
756 if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
757 fCursor ? RT_CURSORW : RT_ICONW ))) return 0;
759 /* If shared icon, check whether it was already loaded */
760 if ( (loadflags & LR_SHARED)
761 && (h = CURSORICON_FindSharedIcon( hInstance, hRsrc ) ) != 0 )
762 return h;
764 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
765 bits = (LPBYTE)LockResource( handle );
766 h = CURSORICON_CreateFromResource( 0, 0, bits, dwBytesInRes,
767 !fCursor, 0x00030000, width, height, loadflags);
768 FreeResource( handle );
770 /* If shared icon, add to icon cache */
772 if ( h && (loadflags & LR_SHARED) )
773 CURSORICON_AddSharedIcon( hInstance, hRsrc, hGroupRsrc, h );
776 return h;
779 /***********************************************************************
780 * CURSORICON_Copy
782 * Make a copy of a cursor or icon.
784 static HGLOBAL16 CURSORICON_Copy( HINSTANCE16 hInstance, HGLOBAL16 handle )
786 char *ptrOld, *ptrNew;
787 int size;
788 HGLOBAL16 hNew;
790 if (!(ptrOld = (char *)GlobalLock16( handle ))) return 0;
791 if (hInstance && !(hInstance = GetExePtr( hInstance ))) return 0;
792 size = GlobalSize16( handle );
793 hNew = GlobalAlloc16( GMEM_MOVEABLE, size );
794 FarSetOwner16( hNew, hInstance );
795 ptrNew = (char *)GlobalLock16( hNew );
796 memcpy( ptrNew, ptrOld, size );
797 GlobalUnlock16( handle );
798 GlobalUnlock16( hNew );
799 return hNew;
802 /*************************************************************************
803 * CURSORICON_ExtCopy
805 * Copies an Image from the Cache if LR_COPYFROMRESOURCE is specified
807 * PARAMS
808 * Handle [I] handle to an Image
809 * nType [I] Type of Handle (IMAGE_CURSOR | IMAGE_ICON)
810 * iDesiredCX [I] The Desired width of the Image
811 * iDesiredCY [I] The desired height of the Image
812 * nFlags [I] The flags from CopyImage
814 * RETURNS
815 * Success: The new handle of the Image
817 * NOTES
818 * LR_COPYDELETEORG and LR_MONOCHROME are currently not implemented.
819 * LR_MONOCHROME should be implemented by CURSORICON_CreateFromResource.
820 * LR_COPYFROMRESOURCE will only work if the Image is in the Cache.
825 HGLOBAL CURSORICON_ExtCopy(HGLOBAL Handle, UINT nType,
826 INT iDesiredCX, INT iDesiredCY,
827 UINT nFlags)
829 HGLOBAL16 hNew=0;
831 TRACE_(icon)("Handle %u, uType %u, iDesiredCX %i, iDesiredCY %i, nFlags %u\n",
832 Handle, nType, iDesiredCX, iDesiredCY, nFlags);
834 if(Handle == 0)
836 return 0;
839 /* Best Fit or Monochrome */
840 if( (nFlags & LR_COPYFROMRESOURCE
841 && (iDesiredCX > 0 || iDesiredCY > 0))
842 || nFlags & LR_MONOCHROME)
844 ICONCACHE* pIconCache = CURSORICON_FindCache(Handle);
846 /* Not Found in Cache, then do a straight copy
848 if(pIconCache == NULL)
850 hNew = CURSORICON_Copy(0, Handle);
851 if(nFlags & LR_COPYFROMRESOURCE)
853 TRACE_(icon)("LR_COPYFROMRESOURCE: Failed to load from cache\n");
856 else
858 int iTargetCY = iDesiredCY, iTargetCX = iDesiredCX;
859 LPBYTE pBits;
860 HANDLE hMem;
861 HRSRC hRsrc;
862 DWORD dwBytesInRes;
863 WORD wResId;
864 CURSORICONDIR *pDir;
865 CURSORICONDIRENTRY *pDirEntry;
866 BOOL bIsIcon = (nType == IMAGE_ICON);
868 /* Completing iDesiredCX CY for Monochrome Bitmaps if needed
870 if(((nFlags & LR_MONOCHROME) && !(nFlags & LR_COPYFROMRESOURCE))
871 || (iDesiredCX == 0 && iDesiredCY == 0))
873 iDesiredCY = GetSystemMetrics(bIsIcon ?
874 SM_CYICON : SM_CYCURSOR);
875 iDesiredCX = GetSystemMetrics(bIsIcon ?
876 SM_CXICON : SM_CXCURSOR);
879 /* Retrieve the CURSORICONDIRENTRY
881 if (!(hMem = LoadResource( pIconCache->hModule ,
882 pIconCache->hGroupRsrc)))
884 return 0;
886 if (!(pDir = (CURSORICONDIR*)LockResource( hMem )))
888 return 0;
891 /* Find Best Fit
893 if(bIsIcon)
895 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(
896 pDir, iDesiredCX, iDesiredCY, 256);
898 else
900 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(
901 pDir, iDesiredCX, iDesiredCY, 1);
904 wResId = pDirEntry->wResId;
905 dwBytesInRes = pDirEntry->dwBytesInRes;
906 FreeResource(hMem);
908 TRACE_(icon)("ResID %u, BytesInRes %lu, Width %d, Height %d DX %d, DY %d\n",
909 wResId, dwBytesInRes, pDirEntry->ResInfo.icon.bWidth,
910 pDirEntry->ResInfo.icon.bHeight, iDesiredCX, iDesiredCY);
912 /* Get the Best Fit
914 if (!(hRsrc = FindResourceW(pIconCache->hModule ,
915 MAKEINTRESOURCEW(wResId), bIsIcon ? RT_ICONW : RT_CURSORW)))
917 return 0;
919 if (!(hMem = LoadResource( pIconCache->hModule , hRsrc )))
921 return 0;
924 pBits = (LPBYTE)LockResource( hMem );
926 if(nFlags & LR_DEFAULTSIZE)
928 iTargetCY = GetSystemMetrics(SM_CYICON);
929 iTargetCX = GetSystemMetrics(SM_CXICON);
932 /* Create a New Icon with the proper dimension
934 hNew = CURSORICON_CreateFromResource( 0, 0, pBits, dwBytesInRes,
935 bIsIcon, 0x00030000, iTargetCX, iTargetCY, nFlags);
936 FreeResource(hMem);
939 else hNew = CURSORICON_Copy(0, Handle);
940 return hNew;
943 /***********************************************************************
944 * CURSORICON_IconToCursor
946 * Converts bitmap to mono and truncates if icon is too large (should
947 * probably do StretchBlt() instead).
949 HCURSOR16 CURSORICON_IconToCursor(HICON16 hIcon, BOOL bSemiTransparent)
951 HCURSOR16 hRet = 0;
952 CURSORICONINFO *pIcon = NULL;
954 if(hIcon)
955 if (!(pIcon = (CURSORICONINFO*)GlobalLock16( hIcon ))) return FALSE;
956 if (pIcon->bPlanes * pIcon->bBitsPerPixel == 1)
958 hRet = CURSORICON_Copy( 0, hIcon );
961 pIcon = GlobalLock16(hRet);
963 pIcon->ptHotSpot.x = pIcon->ptHotSpot.y = 15;
965 GlobalUnlock16(hRet);
967 else
969 BYTE pAndBits[128];
970 BYTE pXorBits[128];
971 int maxx, maxy, ix, iy, bpp = pIcon->bBitsPerPixel;
972 BYTE* psPtr, *pxbPtr = pXorBits;
973 unsigned xor_width, and_width, val_base = 0xffffffff >> (32 - bpp);
974 BYTE* pbc = NULL;
976 CURSORICONINFO cI;
978 TRACE_(icon)("[%04x] %ix%i %ibpp (bogus %ibps)\n",
979 hIcon, pIcon->nWidth, pIcon->nHeight, pIcon->bBitsPerPixel, pIcon->nWidthBytes );
981 xor_width = BITMAP_GetWidthBytes( pIcon->nWidth, bpp );
982 and_width = BITMAP_GetWidthBytes( pIcon->nWidth, 1 );
983 psPtr = (BYTE *)(pIcon + 1) + pIcon->nHeight * and_width;
985 memset(pXorBits, 0, 128);
986 cI.bBitsPerPixel = 1; cI.bPlanes = 1;
987 cI.ptHotSpot.x = cI.ptHotSpot.y = 15;
988 cI.nWidth = 32; cI.nHeight = 32;
989 cI.nWidthBytes = 4; /* 32x1bpp */
991 maxx = (pIcon->nWidth > 32) ? 32 : pIcon->nWidth;
992 maxy = (pIcon->nHeight > 32) ? 32 : pIcon->nHeight;
994 for( iy = 0; iy < maxy; iy++ )
996 unsigned shift = iy % 2;
998 memcpy( pAndBits + iy * 4, (BYTE *)(pIcon + 1) + iy * and_width,
999 (and_width > 4) ? 4 : and_width );
1000 for( ix = 0; ix < maxx; ix++ )
1002 if( bSemiTransparent && ((ix+shift)%2) )
1004 /* set AND bit, XOR bit stays 0 */
1006 pbc = pAndBits + iy * 4 + ix/8;
1007 *pbc |= 0x80 >> (ix%8);
1009 else
1011 /* keep AND bit, set XOR bit */
1013 unsigned *psc = (unsigned*)(psPtr + (ix * bpp)/8);
1014 unsigned val = ((*psc) >> (ix * bpp)%8) & val_base;
1015 if(!PALETTE_Driver->pIsDark(val))
1017 pbc = pxbPtr + ix/8;
1018 *pbc |= 0x80 >> (ix%8);
1022 psPtr += xor_width;
1023 pxbPtr += 4;
1026 hRet = CreateCursorIconIndirect16( 0 , &cI, pAndBits, pXorBits);
1028 if( !hRet ) /* fall back on default drag cursor */
1029 hRet = CURSORICON_Copy( 0 ,
1030 CURSORICON_Load(0,MAKEINTRESOURCEW(OCR_DRAGOBJECT),
1031 GetSystemMetrics(SM_CXCURSOR),
1032 GetSystemMetrics(SM_CYCURSOR), 1, TRUE, 0) );
1035 return hRet;
1039 /***********************************************************************
1040 * LoadCursor (USER.173)
1042 HCURSOR16 WINAPI LoadCursor16( HINSTANCE16 hInstance, LPCSTR name )
1044 return LoadCursorA( hInstance, name );
1048 /***********************************************************************
1049 * LoadIcon (USER.174)
1051 HICON16 WINAPI LoadIcon16( HINSTANCE16 hInstance, LPCSTR name )
1053 return LoadIconA( hInstance, name );
1057 /***********************************************************************
1058 * CreateCursor (USER.406)
1060 HCURSOR16 WINAPI CreateCursor16( HINSTANCE16 hInstance,
1061 INT16 xHotSpot, INT16 yHotSpot,
1062 INT16 nWidth, INT16 nHeight,
1063 LPCVOID lpANDbits, LPCVOID lpXORbits )
1065 CURSORICONINFO info;
1067 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1068 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1070 info.ptHotSpot.x = xHotSpot;
1071 info.ptHotSpot.y = yHotSpot;
1072 info.nWidth = nWidth;
1073 info.nHeight = nHeight;
1074 info.nWidthBytes = 0;
1075 info.bPlanes = 1;
1076 info.bBitsPerPixel = 1;
1078 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1082 /***********************************************************************
1083 * CreateCursor (USER32.@)
1085 HCURSOR WINAPI CreateCursor( HINSTANCE hInstance,
1086 INT xHotSpot, INT yHotSpot,
1087 INT nWidth, INT nHeight,
1088 LPCVOID lpANDbits, LPCVOID lpXORbits )
1090 CURSORICONINFO info;
1092 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1093 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1095 info.ptHotSpot.x = xHotSpot;
1096 info.ptHotSpot.y = yHotSpot;
1097 info.nWidth = nWidth;
1098 info.nHeight = nHeight;
1099 info.nWidthBytes = 0;
1100 info.bPlanes = 1;
1101 info.bBitsPerPixel = 1;
1103 return CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
1107 /***********************************************************************
1108 * CreateIcon (USER.407)
1110 HICON16 WINAPI CreateIcon16( HINSTANCE16 hInstance, INT16 nWidth,
1111 INT16 nHeight, BYTE bPlanes, BYTE bBitsPixel,
1112 LPCVOID lpANDbits, LPCVOID lpXORbits )
1114 CURSORICONINFO info;
1116 TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1117 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1119 info.ptHotSpot.x = ICON_HOTSPOT;
1120 info.ptHotSpot.y = ICON_HOTSPOT;
1121 info.nWidth = nWidth;
1122 info.nHeight = nHeight;
1123 info.nWidthBytes = 0;
1124 info.bPlanes = bPlanes;
1125 info.bBitsPerPixel = bBitsPixel;
1127 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1131 /***********************************************************************
1132 * CreateIcon (USER32.@)
1134 * Creates an icon based on the specified bitmaps. The bitmaps must be
1135 * provided in a device dependent format and will be resized to
1136 * (SM_CXICON,SM_CYICON) and depth converted to match the screen's color
1137 * depth. The provided bitmaps must be top-down bitmaps.
1138 * Although Windows does not support 15bpp(*) this API must support it
1139 * for Winelib applications.
1141 * (*) Windows does not support 15bpp but it supports the 555 RGB 16bpp
1142 * format!
1144 * BUGS
1146 * - The provided bitmaps are not resized!
1147 * - The documentation says the lpXORbits bitmap must be in a device
1148 * dependent format. But we must still resize it and perform depth
1149 * conversions if necessary.
1150 * - I'm a bit unsure about the how the 'device dependent format' thing works.
1151 * I did some tests on windows and found that if you provide a 16bpp bitmap
1152 * in lpXORbits, then its format but be 565 RGB if the screen's bit depth
1153 * is 16bpp but it must be 555 RGB if the screen's bit depth is anything
1154 * else. I don't know if this is part of the GDI specs or if this is a
1155 * quirk of the graphics card driver.
1156 * - You may think that we check whether the bit depths match or not
1157 * as an optimization. But the truth is that the conversion using
1158 * CreateDIBitmap does not work for some bit depth (e.g. 8bpp) and I have
1159 * no idea why.
1160 * - I'm pretty sure that all the things we do in CreateIcon should
1161 * also be done in CreateIconIndirect...
1163 HICON WINAPI CreateIcon(
1164 HINSTANCE hInstance, /* the application's hInstance, currently unused */
1165 INT nWidth, /* the width of the provided bitmaps */
1166 INT nHeight, /* the height of the provided bitmaps */
1167 BYTE bPlanes, /* the number of planes in the provided bitmaps */
1168 BYTE bBitsPixel, /* the number of bits per pixel of the lpXORbits bitmap */
1169 LPCVOID lpANDbits, /* a monochrome bitmap representing the icon's mask */
1170 LPCVOID lpXORbits /* the icon's 'color' bitmap */
1173 HICON hIcon;
1174 HDC hdc;
1176 TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1177 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1179 hdc=GetDC(0);
1180 if (!hdc)
1181 return 0;
1183 if (GetDeviceCaps(hdc,BITSPIXEL)==bBitsPixel) {
1184 CURSORICONINFO info;
1186 info.ptHotSpot.x = ICON_HOTSPOT;
1187 info.ptHotSpot.y = ICON_HOTSPOT;
1188 info.nWidth = nWidth;
1189 info.nHeight = nHeight;
1190 info.nWidthBytes = 0;
1191 info.bPlanes = bPlanes;
1192 info.bBitsPerPixel = bBitsPixel;
1194 hIcon=CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
1195 } else {
1196 ICONINFO iinfo;
1197 BITMAPINFO bmi;
1199 iinfo.fIcon=TRUE;
1200 iinfo.xHotspot=ICON_HOTSPOT;
1201 iinfo.yHotspot=ICON_HOTSPOT;
1202 iinfo.hbmMask=CreateBitmap(nWidth,nHeight,1,1,lpANDbits);
1204 bmi.bmiHeader.biSize=sizeof(bmi.bmiHeader);
1205 bmi.bmiHeader.biWidth=nWidth;
1206 bmi.bmiHeader.biHeight=-nHeight;
1207 bmi.bmiHeader.biPlanes=bPlanes;
1208 bmi.bmiHeader.biBitCount=bBitsPixel;
1209 bmi.bmiHeader.biCompression=BI_RGB;
1210 bmi.bmiHeader.biSizeImage=0;
1211 bmi.bmiHeader.biXPelsPerMeter=0;
1212 bmi.bmiHeader.biYPelsPerMeter=0;
1213 bmi.bmiHeader.biClrUsed=0;
1214 bmi.bmiHeader.biClrImportant=0;
1216 iinfo.hbmColor = CreateDIBitmap( hdc, &bmi.bmiHeader,
1217 CBM_INIT, lpXORbits,
1218 &bmi, DIB_RGB_COLORS );
1220 hIcon=CreateIconIndirect(&iinfo);
1221 DeleteObject(iinfo.hbmMask);
1222 DeleteObject(iinfo.hbmColor);
1224 ReleaseDC(0,hdc);
1225 return hIcon;
1229 /***********************************************************************
1230 * CreateCursorIconIndirect (USER.408)
1232 HGLOBAL16 WINAPI CreateCursorIconIndirect16( HINSTANCE16 hInstance,
1233 CURSORICONINFO *info,
1234 LPCVOID lpANDbits,
1235 LPCVOID lpXORbits )
1237 HGLOBAL16 handle;
1238 char *ptr;
1239 int sizeAnd, sizeXor;
1241 hInstance = GetExePtr( hInstance ); /* Make it a module handle */
1242 if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
1243 info->nWidthBytes = BITMAP_GetWidthBytes(info->nWidth,info->bBitsPerPixel);
1244 sizeXor = info->nHeight * info->nWidthBytes;
1245 sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
1246 if (!(handle = GlobalAlloc16( GMEM_MOVEABLE,
1247 sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
1248 return 0;
1249 FarSetOwner16( handle, hInstance );
1250 ptr = (char *)GlobalLock16( handle );
1251 memcpy( ptr, info, sizeof(*info) );
1252 memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
1253 memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
1254 GlobalUnlock16( handle );
1255 return handle;
1259 /***********************************************************************
1260 * CopyIcon (USER.368)
1262 HICON16 WINAPI CopyIcon16( HINSTANCE16 hInstance, HICON16 hIcon )
1264 TRACE_(icon)("%04x %04x\n", hInstance, hIcon );
1265 return CURSORICON_Copy( hInstance, hIcon );
1269 /***********************************************************************
1270 * CopyIcon (USER32.@)
1272 HICON WINAPI CopyIcon( HICON hIcon )
1274 TRACE_(icon)("%04x\n", hIcon );
1275 return CURSORICON_Copy( 0, hIcon );
1279 /***********************************************************************
1280 * CopyCursor (USER.369)
1282 HCURSOR16 WINAPI CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
1284 TRACE_(cursor)("%04x %04x\n", hInstance, hCursor );
1285 return CURSORICON_Copy( hInstance, hCursor );
1288 /**********************************************************************
1289 * DestroyIcon32 (USER.610)
1291 * This routine is actually exported from Win95 USER under the name
1292 * DestroyIcon32 ... The behaviour implemented here should mimic
1293 * the Win95 one exactly, especially the return values, which
1294 * depend on the setting of various flags.
1296 WORD WINAPI CURSORICON_Destroy( HGLOBAL16 handle, UINT16 flags )
1298 WORD retv;
1300 TRACE_(icon)("(%04x, %04x)\n", handle, flags );
1302 /* Check whether destroying active cursor */
1304 if ( hActiveCursor == handle )
1306 ERR_(cursor)("Destroying active cursor!\n" );
1307 SetCursor( 0 );
1310 /* Try shared cursor/icon first */
1312 if ( !(flags & CID_NONSHARED) )
1314 INT count = CURSORICON_DelSharedIcon( handle );
1316 if ( count != -1 )
1317 return (flags & CID_WIN32)? TRUE : (count == 0);
1319 /* FIXME: OEM cursors/icons should be recognized */
1322 /* Now assume non-shared cursor/icon */
1324 retv = GlobalFree16( handle );
1325 return (flags & CID_RESOURCE)? retv : TRUE;
1328 /***********************************************************************
1329 * DestroyIcon (USER.457)
1331 BOOL16 WINAPI DestroyIcon16( HICON16 hIcon )
1333 return CURSORICON_Destroy( hIcon, 0 );
1336 /***********************************************************************
1337 * DestroyIcon (USER32.@)
1339 BOOL WINAPI DestroyIcon( HICON hIcon )
1341 return CURSORICON_Destroy( hIcon, CID_WIN32 );
1344 /***********************************************************************
1345 * DestroyCursor (USER.458)
1347 BOOL16 WINAPI DestroyCursor16( HCURSOR16 hCursor )
1349 return CURSORICON_Destroy( hCursor, 0 );
1352 /***********************************************************************
1353 * DestroyCursor (USER32.@)
1355 BOOL WINAPI DestroyCursor( HCURSOR hCursor )
1357 return CURSORICON_Destroy( hCursor, CID_WIN32 );
1361 /***********************************************************************
1362 * DrawIcon (USER.84)
1364 BOOL16 WINAPI DrawIcon16( HDC16 hdc, INT16 x, INT16 y, HICON16 hIcon )
1366 return DrawIcon( hdc, x, y, hIcon );
1370 /***********************************************************************
1371 * DrawIcon (USER32.@)
1373 BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
1375 CURSORICONINFO *ptr;
1376 HDC hMemDC;
1377 HBITMAP hXorBits, hAndBits;
1378 COLORREF oldFg, oldBg;
1380 if (!(ptr = (CURSORICONINFO *)GlobalLock16( hIcon ))) return FALSE;
1381 if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
1382 hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1,
1383 (char *)(ptr+1) );
1384 hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
1385 ptr->bBitsPerPixel, (char *)(ptr + 1)
1386 + ptr->nHeight * BITMAP_GetWidthBytes(ptr->nWidth,1) );
1387 oldFg = SetTextColor( hdc, RGB(0,0,0) );
1388 oldBg = SetBkColor( hdc, RGB(255,255,255) );
1390 if (hXorBits && hAndBits)
1392 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1393 BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
1394 SelectObject( hMemDC, hXorBits );
1395 BitBlt(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
1396 SelectObject( hMemDC, hBitTemp );
1398 DeleteDC( hMemDC );
1399 if (hXorBits) DeleteObject( hXorBits );
1400 if (hAndBits) DeleteObject( hAndBits );
1401 GlobalUnlock16( hIcon );
1402 SetTextColor( hdc, oldFg );
1403 SetBkColor( hdc, oldBg );
1404 return TRUE;
1408 /***********************************************************************
1409 * IconSize (USER.86)
1411 * See "Undocumented Windows". Used by W2.0 paint.exe.
1413 DWORD WINAPI IconSize16( void )
1415 return MAKELONG(GetSystemMetrics(SM_CYICON), GetSystemMetrics(SM_CXICON));
1419 /***********************************************************************
1420 * DumpIcon (USER.459)
1422 DWORD WINAPI DumpIcon16( SEGPTR pInfo, WORD *lpLen,
1423 SEGPTR *lpXorBits, SEGPTR *lpAndBits )
1425 CURSORICONINFO *info = MapSL( pInfo );
1426 int sizeAnd, sizeXor;
1428 if (!info) return 0;
1429 sizeXor = info->nHeight * info->nWidthBytes;
1430 sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
1431 if (lpAndBits) *lpAndBits = pInfo + sizeof(CURSORICONINFO);
1432 if (lpXorBits) *lpXorBits = pInfo + sizeof(CURSORICONINFO) + sizeAnd;
1433 if (lpLen) *lpLen = sizeof(CURSORICONINFO) + sizeAnd + sizeXor;
1434 return MAKELONG( sizeXor, sizeXor );
1438 /***********************************************************************
1439 * SetCursor (USER.69)
1441 HCURSOR16 WINAPI SetCursor16( HCURSOR16 hCursor )
1443 return (HCURSOR16)SetCursor( hCursor );
1447 /***********************************************************************
1448 * SetCursor (USER32.@)
1449 * RETURNS:
1450 * A handle to the previous cursor shape.
1452 HCURSOR WINAPI SetCursor(
1453 HCURSOR hCursor /* [in] Handle of cursor to show */
1455 HCURSOR hOldCursor;
1457 if (hCursor == hActiveCursor) return hActiveCursor; /* No change */
1458 TRACE_(cursor)("%04x\n", hCursor );
1459 hOldCursor = hActiveCursor;
1460 hActiveCursor = hCursor;
1461 /* Change the cursor shape only if it is visible */
1462 if (CURSOR_ShowCount >= 0)
1464 USER_Driver.pSetCursor( (CURSORICONINFO*)GlobalLock16( hActiveCursor ) );
1465 GlobalUnlock16( hActiveCursor );
1467 return hOldCursor;
1471 /***********************************************************************
1472 * SetCursorPos (USER.70)
1474 void WINAPI SetCursorPos16( INT16 x, INT16 y )
1476 SetCursorPos( x, y );
1480 /***********************************************************************
1481 * SetCursorPos (USER32.@)
1483 BOOL WINAPI SetCursorPos( INT x, INT y )
1485 USER_Driver.pMoveCursor( x, y );
1486 return TRUE;
1490 /***********************************************************************
1491 * ShowCursor (USER.71)
1493 INT16 WINAPI ShowCursor16( BOOL16 bShow )
1495 return ShowCursor( bShow );
1499 /***********************************************************************
1500 * ShowCursor (USER32.@)
1502 INT WINAPI ShowCursor( BOOL bShow )
1504 TRACE_(cursor)("%d, count=%d\n",
1505 bShow, CURSOR_ShowCount );
1507 if (bShow)
1509 if (++CURSOR_ShowCount == 0) /* Show it */
1511 USER_Driver.pSetCursor( (CURSORICONINFO*)GlobalLock16( hActiveCursor ) );
1512 GlobalUnlock16( hActiveCursor );
1515 else
1517 if (--CURSOR_ShowCount == -1) /* Hide it */
1518 USER_Driver.pSetCursor( NULL );
1520 return CURSOR_ShowCount;
1524 /***********************************************************************
1525 * GetCursor (USER.247)
1527 HCURSOR16 WINAPI GetCursor16(void)
1529 return hActiveCursor;
1533 /***********************************************************************
1534 * GetCursor (USER32.@)
1536 HCURSOR WINAPI GetCursor(void)
1538 return hActiveCursor;
1542 /***********************************************************************
1543 * ClipCursor (USER.16)
1545 BOOL16 WINAPI ClipCursor16( const RECT16 *rect )
1547 if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1548 else CONV_RECT16TO32( rect, &CURSOR_ClipRect );
1549 return TRUE;
1553 /***********************************************************************
1554 * ClipCursor (USER32.@)
1556 BOOL WINAPI ClipCursor( const RECT *rect )
1558 if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1559 else CopyRect( &CURSOR_ClipRect, rect );
1560 return TRUE;
1564 /***********************************************************************
1565 * GetClipCursor (USER.309)
1567 void WINAPI GetClipCursor16( RECT16 *rect )
1569 if (rect) CONV_RECT32TO16( &CURSOR_ClipRect, rect );
1573 /***********************************************************************
1574 * GetClipCursor (USER32.@)
1576 BOOL WINAPI GetClipCursor( RECT *rect )
1578 if (rect)
1580 CopyRect( rect, &CURSOR_ClipRect );
1581 return TRUE;
1583 return FALSE;
1586 /**********************************************************************
1587 * LookupIconIdFromDirectoryEx (USER.364)
1589 * FIXME: exact parameter sizes
1591 INT16 WINAPI LookupIconIdFromDirectoryEx16( LPBYTE xdir, BOOL16 bIcon,
1592 INT16 width, INT16 height, UINT16 cFlag )
1594 CURSORICONDIR *dir = (CURSORICONDIR*)xdir;
1595 UINT16 retVal = 0;
1596 if( dir && !dir->idReserved && (dir->idType & 3) )
1598 CURSORICONDIRENTRY* entry;
1599 HDC hdc;
1600 UINT palEnts;
1601 int colors;
1602 hdc = GetDC(0);
1603 palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
1604 if (palEnts == 0)
1605 palEnts = 256;
1606 colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
1608 ReleaseDC(0, hdc);
1610 if( bIcon )
1611 entry = CURSORICON_FindBestIcon( dir, width, height, colors );
1612 else
1613 entry = CURSORICON_FindBestCursor( dir, width, height, 1);
1615 if( entry ) retVal = entry->wResId;
1617 else WARN_(cursor)("invalid resource directory\n");
1618 return retVal;
1621 /**********************************************************************
1622 * LookupIconIdFromDirectoryEx (USER32.@)
1624 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE dir, BOOL bIcon,
1625 INT width, INT height, UINT cFlag )
1627 return LookupIconIdFromDirectoryEx16( dir, bIcon, width, height, cFlag );
1630 /**********************************************************************
1631 * LookupIconIdFromDirectory (USER.???)
1633 INT16 WINAPI LookupIconIdFromDirectory16( LPBYTE dir, BOOL16 bIcon )
1635 return LookupIconIdFromDirectoryEx16( dir, bIcon,
1636 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1637 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1640 /**********************************************************************
1641 * LookupIconIdFromDirectory (USER32.@)
1643 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1645 return LookupIconIdFromDirectoryEx( dir, bIcon,
1646 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1647 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1650 /**********************************************************************
1651 * GetIconID (USER.455)
1653 WORD WINAPI GetIconID16( HGLOBAL16 hResource, DWORD resType )
1655 LPBYTE lpDir = (LPBYTE)GlobalLock16(hResource);
1657 TRACE_(cursor)("hRes=%04x, entries=%i\n",
1658 hResource, lpDir ? ((CURSORICONDIR*)lpDir)->idCount : 0);
1660 switch(resType)
1662 case RT_CURSOR16:
1663 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, FALSE,
1664 GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1665 case RT_ICON16:
1666 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, TRUE,
1667 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0 );
1668 default:
1669 WARN_(cursor)("invalid res type %ld\n", resType );
1671 return 0;
1674 /**********************************************************************
1675 * LoadCursorIconHandler (USER.336)
1677 * Supposed to load resources of Windows 2.x applications.
1679 HGLOBAL16 WINAPI LoadCursorIconHandler16( HGLOBAL16 hResource, HMODULE16 hModule, HRSRC16 hRsrc )
1681 FIXME_(cursor)("(%04x,%04x,%04x): old 2.x resources are not supported!\n",
1682 hResource, hModule, hRsrc);
1683 return (HGLOBAL16)0;
1686 /**********************************************************************
1687 * LoadDIBIconHandler (USER.357)
1689 * RT_ICON resource loader, installed by USER_SignalProc when module
1690 * is initialized.
1692 HGLOBAL16 WINAPI LoadDIBIconHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1694 /* If hResource is zero we must allocate a new memory block, if it's
1695 * non-zero but GlobalLock() returns NULL then it was discarded and
1696 * we have to recommit some memory, otherwise we just need to check
1697 * the block size. See LoadProc() in 16-bit SDK for more.
1700 hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1701 if( hMemObj )
1703 LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1704 hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1705 SizeofResource16(hModule, hRsrc), TRUE, 0x00030000,
1706 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR );
1708 return hMemObj;
1711 /**********************************************************************
1712 * LoadDIBCursorHandler (USER.356)
1714 * RT_CURSOR resource loader. Same as above.
1716 HGLOBAL16 WINAPI LoadDIBCursorHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1718 hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1719 if( hMemObj )
1721 LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1722 hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1723 SizeofResource16(hModule, hRsrc), FALSE, 0x00030000,
1724 GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1726 return hMemObj;
1729 /**********************************************************************
1730 * LoadIconHandler (USER.456)
1732 HICON16 WINAPI LoadIconHandler16( HGLOBAL16 hResource, BOOL16 bNew )
1734 LPBYTE bits = (LPBYTE)LockResource16( hResource );
1736 TRACE_(cursor)("hRes=%04x\n",hResource);
1738 return CURSORICON_CreateFromResource( 0, 0, bits, 0, TRUE,
1739 bNew ? 0x00030000 : 0x00020000, 0, 0, LR_DEFAULTCOLOR );
1742 /***********************************************************************
1743 * LoadCursorW (USER32.@)
1745 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
1747 return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0,
1748 LR_SHARED | LR_DEFAULTSIZE );
1751 /***********************************************************************
1752 * LoadCursorA (USER32.@)
1754 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
1756 return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0,
1757 LR_SHARED | LR_DEFAULTSIZE );
1760 /***********************************************************************
1761 * LoadCursorFromFileW (USER32.@)
1763 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
1765 return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0,
1766 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1769 /***********************************************************************
1770 * LoadCursorFromFileA (USER32.@)
1772 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
1774 return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0,
1775 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1778 /***********************************************************************
1779 * LoadIconW (USER32.@)
1781 HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
1783 return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0,
1784 LR_SHARED | LR_DEFAULTSIZE );
1787 /***********************************************************************
1788 * LoadIconA (USER32.@)
1790 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
1792 return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0,
1793 LR_SHARED | LR_DEFAULTSIZE );
1796 /**********************************************************************
1797 * GetIconInfo (USER.395)
1799 BOOL16 WINAPI GetIconInfo16(HICON16 hIcon,LPICONINFO16 iconinfo)
1801 ICONINFO ii32;
1802 BOOL16 ret = GetIconInfo((HICON)hIcon, &ii32);
1804 iconinfo->fIcon = ii32.fIcon;
1805 iconinfo->xHotspot = ii32.xHotspot;
1806 iconinfo->yHotspot = ii32.yHotspot;
1807 iconinfo->hbmMask = ii32.hbmMask;
1808 iconinfo->hbmColor = ii32.hbmColor;
1809 return ret;
1812 /**********************************************************************
1813 * GetIconInfo (USER32.@)
1815 BOOL WINAPI GetIconInfo(HICON hIcon,PICONINFO iconinfo) {
1816 CURSORICONINFO *ciconinfo;
1818 ciconinfo = GlobalLock16(hIcon);
1819 if (!ciconinfo)
1820 return FALSE;
1822 if ( (ciconinfo->ptHotSpot.x == ICON_HOTSPOT) &&
1823 (ciconinfo->ptHotSpot.y == ICON_HOTSPOT) )
1825 iconinfo->fIcon = TRUE;
1826 iconinfo->xHotspot = ciconinfo->nWidth / 2;
1827 iconinfo->yHotspot = ciconinfo->nHeight / 2;
1829 else
1831 iconinfo->fIcon = FALSE;
1832 iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
1833 iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
1836 iconinfo->hbmColor = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1837 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
1838 (char *)(ciconinfo + 1)
1839 + ciconinfo->nHeight *
1840 BITMAP_GetWidthBytes (ciconinfo->nWidth,1) );
1841 iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1842 1, 1, (char *)(ciconinfo + 1));
1844 GlobalUnlock16(hIcon);
1846 return TRUE;
1849 /**********************************************************************
1850 * CreateIconIndirect (USER32.@)
1852 HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
1854 BITMAP bmpXor,bmpAnd;
1855 HICON hObj;
1856 int sizeXor,sizeAnd;
1858 GetObjectA( iconinfo->hbmColor, sizeof(bmpXor), &bmpXor );
1859 GetObjectA( iconinfo->hbmMask, sizeof(bmpAnd), &bmpAnd );
1861 sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
1862 sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
1864 hObj = GlobalAlloc16( GMEM_MOVEABLE,
1865 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
1866 if (hObj)
1868 CURSORICONINFO *info;
1870 info = (CURSORICONINFO *)GlobalLock16( hObj );
1872 /* If we are creating an icon, the hotspot is unused */
1873 if (iconinfo->fIcon)
1875 info->ptHotSpot.x = ICON_HOTSPOT;
1876 info->ptHotSpot.y = ICON_HOTSPOT;
1878 else
1880 info->ptHotSpot.x = iconinfo->xHotspot;
1881 info->ptHotSpot.y = iconinfo->yHotspot;
1884 info->nWidth = bmpXor.bmWidth;
1885 info->nHeight = bmpXor.bmHeight;
1886 info->nWidthBytes = bmpXor.bmWidthBytes;
1887 info->bPlanes = bmpXor.bmPlanes;
1888 info->bBitsPerPixel = bmpXor.bmBitsPixel;
1890 /* Transfer the bitmap bits to the CURSORICONINFO structure */
1892 GetBitmapBits( iconinfo->hbmMask ,sizeAnd,(char*)(info + 1) );
1893 GetBitmapBits( iconinfo->hbmColor,sizeXor,(char*)(info + 1) +sizeAnd);
1894 GlobalUnlock16( hObj );
1896 return hObj;
1900 /**********************************************************************
1901 * DrawIconEx (USER.394)
1903 BOOL16 WINAPI DrawIconEx16 (HDC16 hdc, INT16 xLeft, INT16 yTop, HICON16 hIcon,
1904 INT16 cxWidth, INT16 cyWidth, UINT16 istep,
1905 HBRUSH16 hbr, UINT16 flags)
1907 return DrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
1908 istep, hbr, flags);
1912 /******************************************************************************
1913 * DrawIconEx (USER32.@) Draws an icon or cursor on device context
1915 * NOTES
1916 * Why is this using SM_CXICON instead of SM_CXCURSOR?
1918 * PARAMS
1919 * hdc [I] Handle to device context
1920 * x0 [I] X coordinate of upper left corner
1921 * y0 [I] Y coordinate of upper left corner
1922 * hIcon [I] Handle to icon to draw
1923 * cxWidth [I] Width of icon
1924 * cyWidth [I] Height of icon
1925 * istep [I] Index of frame in animated cursor
1926 * hbr [I] Handle to background brush
1927 * flags [I] Icon-drawing flags
1929 * RETURNS
1930 * Success: TRUE
1931 * Failure: FALSE
1933 BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
1934 INT cxWidth, INT cyWidth, UINT istep,
1935 HBRUSH hbr, UINT flags )
1937 CURSORICONINFO *ptr = (CURSORICONINFO *)GlobalLock16 (hIcon);
1938 HDC hDC_off = 0, hMemDC = CreateCompatibleDC (hdc);
1939 BOOL result = FALSE, DoOffscreen;
1940 HBITMAP hB_off = 0, hOld = 0;
1942 if (!ptr) return FALSE;
1943 TRACE_(icon)("(hdc=%x,pos=%d.%d,hicon=%x,extend=%d.%d,istep=%d,br=%x,flags=0x%08x)\n",
1944 hdc,x0,y0,hIcon,cxWidth,cyWidth,istep,hbr,flags
1947 if (istep)
1948 FIXME_(icon)("Ignoring istep=%d\n", istep);
1949 if (flags & DI_COMPAT)
1950 FIXME_(icon)("Ignoring flag DI_COMPAT\n");
1952 if (!flags) {
1953 FIXME_(icon)("no flags set? setting to DI_NORMAL\n");
1954 flags = DI_NORMAL;
1957 /* Calculate the size of the destination image. */
1958 if (cxWidth == 0)
1960 if (flags & DI_DEFAULTSIZE)
1961 cxWidth = GetSystemMetrics (SM_CXICON);
1962 else
1963 cxWidth = ptr->nWidth;
1965 if (cyWidth == 0)
1967 if (flags & DI_DEFAULTSIZE)
1968 cyWidth = GetSystemMetrics (SM_CYICON);
1969 else
1970 cyWidth = ptr->nHeight;
1973 DoOffscreen = (GetObjectType( hbr ) == OBJ_BRUSH);
1975 if (DoOffscreen) {
1976 RECT r;
1978 r.left = 0;
1979 r.top = 0;
1980 r.right = cxWidth;
1981 r.bottom = cxWidth;
1983 hDC_off = CreateCompatibleDC(hdc);
1984 hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth);
1985 if (hDC_off && hB_off) {
1986 hOld = SelectObject(hDC_off, hB_off);
1987 FillRect(hDC_off, &r, hbr);
1991 if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
1993 HBITMAP hXorBits, hAndBits;
1994 COLORREF oldFg, oldBg;
1995 INT nStretchMode;
1997 nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
1999 hXorBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
2000 ptr->bPlanes, ptr->bBitsPerPixel,
2001 (char *)(ptr + 1)
2002 + ptr->nHeight *
2003 BITMAP_GetWidthBytes(ptr->nWidth,1) );
2004 hAndBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
2005 1, 1, (char *)(ptr+1) );
2006 oldFg = SetTextColor( hdc, RGB(0,0,0) );
2007 oldBg = SetBkColor( hdc, RGB(255,255,255) );
2009 if (hXorBits && hAndBits)
2011 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
2012 if (flags & DI_MASK)
2014 if (DoOffscreen)
2015 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
2016 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
2017 else
2018 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
2019 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
2021 SelectObject( hMemDC, hXorBits );
2022 if (flags & DI_IMAGE)
2024 if (DoOffscreen)
2025 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
2026 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
2027 else
2028 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
2029 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
2031 SelectObject( hMemDC, hBitTemp );
2032 result = TRUE;
2035 SetTextColor( hdc, oldFg );
2036 SetBkColor( hdc, oldBg );
2037 if (hXorBits) DeleteObject( hXorBits );
2038 if (hAndBits) DeleteObject( hAndBits );
2039 SetStretchBltMode (hdc, nStretchMode);
2040 if (DoOffscreen) {
2041 BitBlt(hdc, x0, y0, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
2042 SelectObject(hDC_off, hOld);
2045 if (hMemDC) DeleteDC( hMemDC );
2046 if (hDC_off) DeleteDC(hDC_off);
2047 if (hB_off) DeleteObject(hB_off);
2048 GlobalUnlock16( hIcon );
2049 return result;
2052 /***********************************************************************
2053 * DIB_FixColorsToLoadflags
2055 * Change color table entries when LR_LOADTRANSPARENT or LR_LOADMAP3DCOLORS
2056 * are in loadflags
2058 static void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags, BYTE pix)
2060 int colors;
2061 COLORREF c_W, c_S, c_F, c_L, c_C;
2062 int incr,i;
2063 RGBQUAD *ptr;
2065 if (bmi->bmiHeader.biBitCount > 8) return;
2066 if (bmi->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)) incr = 4;
2067 else if (bmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) incr = 3;
2068 else {
2069 WARN_(resource)("Wrong bitmap header size!\n");
2070 return;
2072 colors = bmi->bmiHeader.biClrUsed;
2073 if (!colors && (bmi->bmiHeader.biBitCount <= 8))
2074 colors = 1 << bmi->bmiHeader.biBitCount;
2075 c_W = GetSysColor(COLOR_WINDOW);
2076 c_S = GetSysColor(COLOR_3DSHADOW);
2077 c_F = GetSysColor(COLOR_3DFACE);
2078 c_L = GetSysColor(COLOR_3DLIGHT);
2079 if (loadflags & LR_LOADTRANSPARENT) {
2080 switch (bmi->bmiHeader.biBitCount) {
2081 case 1: pix = pix >> 7; break;
2082 case 4: pix = pix >> 4; break;
2083 case 8: break;
2084 default:
2085 WARN_(resource)("(%d): Unsupported depth\n", bmi->bmiHeader.biBitCount);
2086 return;
2088 if (pix >= colors) {
2089 WARN_(resource)("pixel has color index greater than biClrUsed!\n");
2090 return;
2092 if (loadflags & LR_LOADMAP3DCOLORS) c_W = c_F;
2093 ptr = (RGBQUAD*)((char*)bmi->bmiColors+pix*incr);
2094 ptr->rgbBlue = GetBValue(c_W);
2095 ptr->rgbGreen = GetGValue(c_W);
2096 ptr->rgbRed = GetRValue(c_W);
2098 if (loadflags & LR_LOADMAP3DCOLORS)
2099 for (i=0; i<colors; i++) {
2100 ptr = (RGBQUAD*)((char*)bmi->bmiColors+i*incr);
2101 c_C = RGB(ptr->rgbRed, ptr->rgbGreen, ptr->rgbBlue);
2102 if (c_C == RGB(128, 128, 128)) {
2103 ptr->rgbRed = GetRValue(c_S);
2104 ptr->rgbGreen = GetGValue(c_S);
2105 ptr->rgbBlue = GetBValue(c_S);
2106 } else if (c_C == RGB(192, 192, 192)) {
2107 ptr->rgbRed = GetRValue(c_F);
2108 ptr->rgbGreen = GetGValue(c_F);
2109 ptr->rgbBlue = GetBValue(c_F);
2110 } else if (c_C == RGB(223, 223, 223)) {
2111 ptr->rgbRed = GetRValue(c_L);
2112 ptr->rgbGreen = GetGValue(c_L);
2113 ptr->rgbBlue = GetBValue(c_L);
2119 /**********************************************************************
2120 * BITMAP_Load
2122 static HBITMAP BITMAP_Load( HINSTANCE instance,LPCWSTR name, UINT loadflags )
2124 HBITMAP hbitmap = 0;
2125 HRSRC hRsrc;
2126 HGLOBAL handle;
2127 char *ptr = NULL;
2128 BITMAPINFO *info, *fix_info=NULL;
2129 HGLOBAL hFix;
2130 int size;
2132 if (!(loadflags & LR_LOADFROMFILE)) {
2133 if (!instance) /* OEM bitmap */
2135 if (HIWORD((int)name)) return 0;
2136 return USER_Driver.pLoadOEMResource( LOWORD((int)name), OEM_BITMAP );
2139 if (!(hRsrc = FindResourceW( instance, name, RT_BITMAPW ))) return 0;
2140 if (!(handle = LoadResource( instance, hRsrc ))) return 0;
2142 if ((info = (BITMAPINFO *)LockResource( handle )) == NULL) return 0;
2144 else
2146 if (!(ptr = map_fileW( name ))) return 0;
2147 info = (BITMAPINFO *)(ptr + sizeof(BITMAPFILEHEADER));
2149 size = DIB_BitmapInfoSize(info, DIB_RGB_COLORS);
2150 if ((hFix = GlobalAlloc(0, size))) fix_info=GlobalLock(hFix);
2151 if (fix_info) {
2152 BYTE pix;
2154 memcpy(fix_info, info, size);
2155 pix = *((LPBYTE)info+DIB_BitmapInfoSize(info, DIB_RGB_COLORS));
2156 DIB_FixColorsToLoadflags(fix_info, loadflags, pix);
2157 if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
2158 if (screen_dc)
2160 char *bits = (char *)info + size;
2161 if (loadflags & LR_CREATEDIBSECTION) {
2162 DIBSECTION dib;
2163 hbitmap = CreateDIBSection(screen_dc, fix_info, DIB_RGB_COLORS, NULL, 0, 0);
2164 GetObjectA(hbitmap, sizeof(DIBSECTION), &dib);
2165 SetDIBits(screen_dc, hbitmap, 0, dib.dsBm.bmHeight, bits, info,
2166 DIB_RGB_COLORS);
2168 else {
2169 hbitmap = CreateDIBitmap( screen_dc, &fix_info->bmiHeader, CBM_INIT,
2170 bits, fix_info, DIB_RGB_COLORS );
2173 GlobalUnlock(hFix);
2174 GlobalFree(hFix);
2176 if (loadflags & LR_LOADFROMFILE) UnmapViewOfFile( ptr );
2177 return hbitmap;
2181 /***********************************************************************
2182 * LoadImage (USER.389)
2185 HANDLE16 WINAPI LoadImage16( HINSTANCE16 hinst, LPCSTR name, UINT16 type,
2186 INT16 desiredx, INT16 desiredy, UINT16 loadflags)
2188 return LoadImageA( hinst, name, type, desiredx, desiredy, loadflags );
2191 /**********************************************************************
2192 * LoadImageA (USER32.@)
2194 * FIXME: implementation lacks some features, see LR_ defines in windows.h
2197 HANDLE WINAPI LoadImageA( HINSTANCE hinst, LPCSTR name, UINT type,
2198 INT desiredx, INT desiredy, UINT loadflags)
2200 HANDLE res;
2201 LPWSTR u_name;
2203 if (HIWORD(name)) u_name = HEAP_strdupAtoW(GetProcessHeap(), 0, name);
2204 else u_name=(LPWSTR)name;
2205 res = LoadImageW(hinst, u_name, type, desiredx, desiredy, loadflags);
2206 if (HIWORD(name)) HeapFree(GetProcessHeap(), 0, u_name);
2207 return res;
2211 /******************************************************************************
2212 * LoadImageW (USER32.@) Loads an icon, cursor, or bitmap
2214 * PARAMS
2215 * hinst [I] Handle of instance that contains image
2216 * name [I] Name of image
2217 * type [I] Type of image
2218 * desiredx [I] Desired width
2219 * desiredy [I] Desired height
2220 * loadflags [I] Load flags
2222 * RETURNS
2223 * Success: Handle to newly loaded image
2224 * Failure: NULL
2226 * FIXME: Implementation lacks some features, see LR_ defines in windows.h
2228 HANDLE WINAPI LoadImageW( HINSTANCE hinst, LPCWSTR name, UINT type,
2229 INT desiredx, INT desiredy, UINT loadflags )
2231 if (HIWORD(name)) {
2232 TRACE_(resource)("(0x%04x,%p,%d,%d,%d,0x%08x)\n",
2233 hinst,name,type,desiredx,desiredy,loadflags);
2234 } else {
2235 TRACE_(resource)("(0x%04x,%p,%d,%d,%d,0x%08x)\n",
2236 hinst,name,type,desiredx,desiredy,loadflags);
2238 if (loadflags & LR_DEFAULTSIZE) {
2239 if (type == IMAGE_ICON) {
2240 if (!desiredx) desiredx = GetSystemMetrics(SM_CXICON);
2241 if (!desiredy) desiredy = GetSystemMetrics(SM_CYICON);
2242 } else if (type == IMAGE_CURSOR) {
2243 if (!desiredx) desiredx = GetSystemMetrics(SM_CXCURSOR);
2244 if (!desiredy) desiredy = GetSystemMetrics(SM_CYCURSOR);
2247 if (loadflags & LR_LOADFROMFILE) loadflags &= ~LR_SHARED;
2248 switch (type) {
2249 case IMAGE_BITMAP:
2250 return BITMAP_Load( hinst, name, loadflags );
2252 case IMAGE_ICON:
2253 if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
2254 if (screen_dc)
2256 UINT palEnts = GetSystemPaletteEntries(screen_dc, 0, 0, NULL);
2257 if (palEnts == 0) palEnts = 256;
2258 return CURSORICON_Load(hinst, name, desiredx, desiredy,
2259 palEnts, FALSE, loadflags);
2261 break;
2263 case IMAGE_CURSOR:
2264 return CURSORICON_Load(hinst, name, desiredx, desiredy,
2265 1, TRUE, loadflags);
2267 return 0;
2271 /******************************************************************************
2272 * CopyImage (USER.390) Creates new image and copies attributes to it
2275 HICON16 WINAPI CopyImage16( HANDLE16 hnd, UINT16 type, INT16 desiredx,
2276 INT16 desiredy, UINT16 flags )
2278 return (HICON16)CopyImage((HANDLE)hnd, (UINT)type, (INT)desiredx,
2279 (INT)desiredy, (UINT)flags);
2282 /******************************************************************************
2283 * CopyImage (USER32.@) Creates new image and copies attributes to it
2285 * PARAMS
2286 * hnd [I] Handle to image to copy
2287 * type [I] Type of image to copy
2288 * desiredx [I] Desired width of new image
2289 * desiredy [I] Desired height of new image
2290 * flags [I] Copy flags
2292 * RETURNS
2293 * Success: Handle to newly created image
2294 * Failure: NULL
2296 * FIXME: implementation still lacks nearly all features, see LR_*
2297 * defines in windows.h
2299 HICON WINAPI CopyImage( HANDLE hnd, UINT type, INT desiredx,
2300 INT desiredy, UINT flags )
2302 switch (type)
2304 case IMAGE_BITMAP:
2305 return BITMAP_CopyBitmap(hnd);
2306 case IMAGE_ICON:
2307 return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags);
2308 case IMAGE_CURSOR:
2309 /* Should call CURSORICON_ExtCopy but more testing
2310 * needs to be done before we change this
2312 return CopyCursor(hnd);
2314 return 0;
2318 /******************************************************************************
2319 * LoadBitmapW (USER32.@) Loads bitmap from the executable file
2321 * RETURNS
2322 * Success: Handle to specified bitmap
2323 * Failure: NULL
2325 HBITMAP WINAPI LoadBitmapW(
2326 HINSTANCE instance, /* [in] Handle to application instance */
2327 LPCWSTR name) /* [in] Address of bitmap resource name */
2329 return LoadImageW( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2332 /**********************************************************************
2333 * LoadBitmapA (USER32.@)
2335 HBITMAP WINAPI LoadBitmapA( HINSTANCE instance, LPCSTR name )
2337 return LoadImageA( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2340 /**********************************************************************
2341 * LoadBitmap (USER.175)
2343 HBITMAP16 WINAPI LoadBitmap16( HINSTANCE16 instance, LPCSTR name )
2345 return LoadBitmapA( instance, name );