Added RunInThread callout to winedos.
[wine/multimedia.git] / windows / cursoricon.c
blob0122a26e0adb8f717e0785ec286bb22bb1e80331
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 "wine/exception.h"
40 #include "heap.h"
41 #include "palette.h"
42 #include "bitmap.h"
43 #include "cursoricon.h"
44 #include "module.h"
45 #include "debugtools.h"
46 #include "user.h"
47 #include "input.h"
48 #include "message.h"
49 #include "winerror.h"
51 DECLARE_DEBUG_CHANNEL(cursor);
52 DECLARE_DEBUG_CHANNEL(icon);
53 DECLARE_DEBUG_CHANNEL(resource);
55 static HCURSOR hActiveCursor = 0; /* Active cursor */
56 static INT CURSOR_ShowCount = 0; /* Cursor display count */
57 static RECT CURSOR_ClipRect; /* Cursor clipping rect */
59 static HDC screen_dc;
61 /**********************************************************************
62 * ICONCACHE for cursors/icons loaded with LR_SHARED.
64 * FIXME: This should not be allocated on the system heap, but on a
65 * subsystem-global heap (i.e. one for all Win16 processes,
66 * and one for each Win32 process).
68 typedef struct tagICONCACHE
70 struct tagICONCACHE *next;
72 HMODULE hModule;
73 HRSRC hRsrc;
74 HRSRC hGroupRsrc;
75 HANDLE handle;
77 INT count;
79 } ICONCACHE;
81 static ICONCACHE *IconAnchor = NULL;
82 static CRITICAL_SECTION IconCrst = CRITICAL_SECTION_INIT("IconCrst");
83 static WORD ICON_HOTSPOT = 0x4242;
86 /***********************************************************************
87 * map_fileW
89 * Helper function to map a file to memory:
90 * name - file name
91 * [RETURN] ptr - pointer to mapped file
93 static void *map_fileW( LPCWSTR name )
95 HANDLE hFile, hMapping;
96 LPVOID ptr = NULL;
98 hFile = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL,
99 OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0 );
100 if (hFile != INVALID_HANDLE_VALUE)
102 hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
103 CloseHandle( hFile );
104 if (hMapping)
106 ptr = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
107 CloseHandle( hMapping );
110 return ptr;
114 /**********************************************************************
115 * CURSORICON_FindSharedIcon
117 static HANDLE CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
119 HANDLE handle = 0;
120 ICONCACHE *ptr;
122 EnterCriticalSection( &IconCrst );
124 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
125 if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
127 ptr->count++;
128 handle = ptr->handle;
129 break;
132 LeaveCriticalSection( &IconCrst );
134 return handle;
137 /*************************************************************************
138 * CURSORICON_FindCache
140 * Given a handle, find the corresponding cache element
142 * PARAMS
143 * Handle [I] handle to an Image
145 * RETURNS
146 * Success: The cache entry
147 * Failure: NULL
150 static ICONCACHE* CURSORICON_FindCache(HANDLE handle)
152 ICONCACHE *ptr;
153 ICONCACHE *pRet=NULL;
154 BOOL IsFound = FALSE;
155 int count;
157 EnterCriticalSection( &IconCrst );
159 for (count = 0, ptr = IconAnchor; ptr != NULL && !IsFound; ptr = ptr->next, count++ )
161 if ( handle == ptr->handle )
163 IsFound = TRUE;
164 pRet = ptr;
168 LeaveCriticalSection( &IconCrst );
170 return pRet;
173 /**********************************************************************
174 * CURSORICON_AddSharedIcon
176 static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HRSRC hGroupRsrc, HANDLE handle )
178 ICONCACHE *ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(ICONCACHE) );
179 if ( !ptr ) return;
181 ptr->hModule = hModule;
182 ptr->hRsrc = hRsrc;
183 ptr->handle = handle;
184 ptr->hGroupRsrc = hGroupRsrc;
185 ptr->count = 1;
187 EnterCriticalSection( &IconCrst );
188 ptr->next = IconAnchor;
189 IconAnchor = ptr;
190 LeaveCriticalSection( &IconCrst );
193 /**********************************************************************
194 * CURSORICON_DelSharedIcon
196 static INT CURSORICON_DelSharedIcon( HANDLE handle )
198 INT count = -1;
199 ICONCACHE *ptr;
201 EnterCriticalSection( &IconCrst );
203 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
204 if ( ptr->handle == handle )
206 if ( ptr->count > 0 ) ptr->count--;
207 count = ptr->count;
208 break;
211 LeaveCriticalSection( &IconCrst );
213 return count;
216 /**********************************************************************
217 * CURSORICON_FreeModuleIcons
219 void CURSORICON_FreeModuleIcons( HMODULE hModule )
221 ICONCACHE **ptr = &IconAnchor;
223 if ( HIWORD( hModule ) )
224 hModule = MapHModuleLS( hModule );
225 else
226 hModule = GetExePtr( hModule );
228 EnterCriticalSection( &IconCrst );
230 while ( *ptr )
232 if ( (*ptr)->hModule == hModule )
234 ICONCACHE *freePtr = *ptr;
235 *ptr = freePtr->next;
237 GlobalFree16( freePtr->handle );
238 HeapFree( GetProcessHeap(), 0, freePtr );
239 continue;
241 ptr = &(*ptr)->next;
244 LeaveCriticalSection( &IconCrst );
247 /**********************************************************************
248 * CURSORICON_FindBestIcon
250 * Find the icon closest to the requested size and number of colors.
252 static CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
253 int height, int colors )
255 int i;
256 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
257 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
258 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
260 if (dir->idCount < 1)
262 WARN_(icon)("Empty directory!\n" );
263 return NULL;
265 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
267 /* Find Best Fit */
268 iTotalDiff = 0xFFFFFFFF;
269 iColorDiff = 0xFFFFFFFF;
270 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
272 iTempXDiff = abs(width - entry->ResInfo.icon.bWidth);
273 iTempYDiff = abs(height - entry->ResInfo.icon.bHeight);
275 if(iTotalDiff > (iTempXDiff + iTempYDiff))
277 iXDiff = iTempXDiff;
278 iYDiff = iTempYDiff;
279 iTotalDiff = iXDiff + iYDiff;
283 /* Find Best Colors for Best Fit */
284 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
286 if(abs(width - entry->ResInfo.icon.bWidth) == iXDiff &&
287 abs(height - entry->ResInfo.icon.bHeight) == iYDiff)
289 iTempColorDiff = abs(colors - entry->ResInfo.icon.bColorCount);
290 if(iColorDiff > iTempColorDiff)
292 bestEntry = entry;
293 iColorDiff = iTempColorDiff;
298 return bestEntry;
302 /**********************************************************************
303 * CURSORICON_FindBestCursor
305 * Find the cursor closest to the requested size.
306 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
307 * ignored too
309 static CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
310 int width, int height, int color)
312 int i, maxwidth, maxheight;
313 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
315 if (dir->idCount < 1)
317 WARN_(cursor)("Empty directory!\n" );
318 return NULL;
320 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
322 /* Double height to account for AND and XOR masks */
324 height *= 2;
326 /* First find the largest one smaller than or equal to the requested size*/
328 maxwidth = maxheight = 0;
329 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
330 if ((entry->ResInfo.cursor.wWidth <= width) && (entry->ResInfo.cursor.wHeight <= height) &&
331 (entry->ResInfo.cursor.wWidth > maxwidth) && (entry->ResInfo.cursor.wHeight > maxheight) &&
332 (entry->wBitCount == 1))
334 bestEntry = entry;
335 maxwidth = entry->ResInfo.cursor.wWidth;
336 maxheight = entry->ResInfo.cursor.wHeight;
338 if (bestEntry) return bestEntry;
340 /* Now find the smallest one larger than the requested size */
342 maxwidth = maxheight = 255;
343 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
344 if ((entry->ResInfo.cursor.wWidth < maxwidth) && (entry->ResInfo.cursor.wHeight < maxheight) &&
345 (entry->wBitCount == 1))
347 bestEntry = entry;
348 maxwidth = entry->ResInfo.cursor.wWidth;
349 maxheight = entry->ResInfo.cursor.wHeight;
352 return bestEntry;
355 /*********************************************************************
356 * The main purpose of this function is to create fake resource directory
357 * and fake resource entries. There are several reasons for this:
358 * - CURSORICONDIR and CURSORICONFILEDIR differ in sizes and their
359 * fields
360 * There are some "bad" cursor files which do not have
361 * bColorCount initialized but instead one must read this info
362 * directly from corresponding DIB sections
363 * Note: wResId is index to array of pointer returned in ptrs (origin is 1)
365 BOOL CURSORICON_SimulateLoadingFromResourceW( LPWSTR filename, BOOL fCursor,
366 CURSORICONDIR **res, LPBYTE **ptr)
368 LPBYTE _free;
369 CURSORICONFILEDIR *bits;
370 int entries, size, i;
372 *res = NULL;
373 *ptr = NULL;
374 if (!(bits = map_fileW( filename ))) return FALSE;
376 /* FIXME: test for inimated icons
377 * hack to load the first icon from the *.ani file
379 if ( *(LPDWORD)bits==0x46464952 ) /* "RIFF" */
380 { LPBYTE pos = (LPBYTE) bits;
381 FIXME_(cursor)("Animated icons not correctly implemented! %p \n", bits);
383 for (;;)
384 { if (*(LPDWORD)pos==0x6e6f6369) /* "icon" */
385 { FIXME_(cursor)("icon entry found! %p\n", bits);
386 pos+=4;
387 if ( !*(LPWORD) pos==0x2fe) /* iconsize */
388 { goto fail;
390 bits=(CURSORICONFILEDIR*)(pos+4);
391 FIXME_(cursor)("icon size ok. offset=%p \n", bits);
392 break;
394 pos+=2;
395 if (pos>=(LPBYTE)bits+766) goto fail;
398 if (!(entries = bits->idCount)) goto fail;
399 size = sizeof(CURSORICONDIR) + sizeof(CURSORICONDIRENTRY) * (entries - 1);
400 _free = (LPBYTE) size;
402 for (i=0; i < entries; i++)
403 size += bits->idEntries[i].dwDIBSize + (fCursor ? sizeof(POINT16): 0);
405 if (!(*ptr = HeapAlloc( GetProcessHeap(), 0,
406 entries * sizeof (CURSORICONDIRENTRY*)))) goto fail;
407 if (!(*res = HeapAlloc( GetProcessHeap(), 0, size))) goto fail;
409 _free = (LPBYTE)(*res) + (int)_free;
410 memcpy((*res), bits, 6);
411 for (i=0; i<entries; i++)
413 ((LPBYTE*)(*ptr))[i] = _free;
414 if (fCursor) {
415 (*res)->idEntries[i].ResInfo.cursor.wWidth=bits->idEntries[i].bWidth;
416 (*res)->idEntries[i].ResInfo.cursor.wHeight=bits->idEntries[i].bHeight;
417 ((LPPOINT16)_free)->x=bits->idEntries[i].xHotspot;
418 ((LPPOINT16)_free)->y=bits->idEntries[i].yHotspot;
419 _free+=sizeof(POINT16);
420 } else {
421 (*res)->idEntries[i].ResInfo.icon.bWidth=bits->idEntries[i].bWidth;
422 (*res)->idEntries[i].ResInfo.icon.bHeight=bits->idEntries[i].bHeight;
423 (*res)->idEntries[i].ResInfo.icon.bColorCount = bits->idEntries[i].bColorCount;
425 (*res)->idEntries[i].wPlanes=1;
426 (*res)->idEntries[i].wBitCount = ((LPBITMAPINFOHEADER)((LPBYTE)bits +
427 bits->idEntries[i].dwDIBOffset))->biBitCount;
428 (*res)->idEntries[i].dwBytesInRes = bits->idEntries[i].dwDIBSize;
429 (*res)->idEntries[i].wResId=i+1;
431 memcpy(_free,(LPBYTE)bits +bits->idEntries[i].dwDIBOffset,
432 (*res)->idEntries[i].dwBytesInRes);
433 _free += (*res)->idEntries[i].dwBytesInRes;
435 UnmapViewOfFile( bits );
436 return TRUE;
437 fail:
438 if (*res) HeapFree( GetProcessHeap(), 0, *res );
439 if (*ptr) HeapFree( GetProcessHeap(), 0, *ptr );
440 UnmapViewOfFile( bits );
441 return FALSE;
445 /**********************************************************************
446 * CURSORICON_CreateFromResource
448 * Create a cursor or icon from in-memory resource template.
450 * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
451 * with cbSize parameter as well.
453 static HGLOBAL16 CURSORICON_CreateFromResource( HINSTANCE16 hInstance, HGLOBAL16 hObj, LPBYTE bits,
454 UINT cbSize, BOOL bIcon, DWORD dwVersion,
455 INT width, INT height, UINT loadflags )
457 static HDC hdcMem;
458 int sizeAnd, sizeXor;
459 HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
460 BITMAP bmpXor, bmpAnd;
461 POINT16 hotspot;
462 BITMAPINFO *bmi;
463 BOOL DoStretch;
464 INT size;
466 hotspot.x = ICON_HOTSPOT;
467 hotspot.y = ICON_HOTSPOT;
469 TRACE_(cursor)("%08x (%u bytes), ver %08x, %ix%i %s %s\n",
470 (unsigned)bits, cbSize, (unsigned)dwVersion, width, height,
471 bIcon ? "icon" : "cursor", (loadflags & LR_MONOCHROME) ? "mono" : "" );
472 if (dwVersion == 0x00020000)
474 FIXME_(cursor)("\t2.xx resources are not supported\n");
475 return 0;
478 if (bIcon)
479 bmi = (BITMAPINFO *)bits;
480 else /* get the hotspot */
482 POINT16 *pt = (POINT16 *)bits;
483 hotspot = *pt;
484 bmi = (BITMAPINFO *)(pt + 1);
486 size = DIB_BitmapInfoSize( bmi, DIB_RGB_COLORS );
488 if (!width) width = bmi->bmiHeader.biWidth;
489 if (!height) height = bmi->bmiHeader.biHeight/2;
490 DoStretch = (bmi->bmiHeader.biHeight/2 != height) ||
491 (bmi->bmiHeader.biWidth != width);
493 /* Check bitmap header */
495 if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
496 (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) ||
497 bmi->bmiHeader.biCompression != BI_RGB) )
499 WARN_(cursor)("\tinvalid resource bitmap header.\n");
500 return 0;
503 if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
504 if (screen_dc)
506 BITMAPINFO* pInfo;
508 /* Make sure we have room for the monochrome bitmap later on.
509 * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
510 * up to and including the biBitCount. In-memory icon resource
511 * format is as follows:
513 * BITMAPINFOHEADER icHeader // DIB header
514 * RGBQUAD icColors[] // Color table
515 * BYTE icXOR[] // DIB bits for XOR mask
516 * BYTE icAND[] // DIB bits for AND mask
519 if ((pInfo = (BITMAPINFO *)HeapAlloc( GetProcessHeap(), 0,
520 max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))))
522 memcpy( pInfo, bmi, size );
523 pInfo->bmiHeader.biHeight /= 2;
525 /* Create the XOR bitmap */
527 if (DoStretch) {
528 if(bIcon)
530 hXorBits = CreateCompatibleBitmap(screen_dc, width, height);
532 else
534 hXorBits = CreateBitmap(width, height, 1, 1, NULL);
536 if(hXorBits)
538 HBITMAP hOld;
539 BOOL res = FALSE;
541 if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
542 if (hdcMem) {
543 hOld = SelectObject(hdcMem, hXorBits);
544 res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
545 bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2,
546 (char*)bmi + size, pInfo, DIB_RGB_COLORS, SRCCOPY);
547 SelectObject(hdcMem, hOld);
549 if (!res) { DeleteObject(hXorBits); hXorBits = 0; }
551 } else hXorBits = CreateDIBitmap( screen_dc, &pInfo->bmiHeader,
552 CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS );
553 if( hXorBits )
555 char* xbits = (char *)bmi + size +
556 DIB_GetDIBImageBytes(bmi->bmiHeader.biWidth,
557 bmi->bmiHeader.biHeight,
558 bmi->bmiHeader.biBitCount) / 2;
560 pInfo->bmiHeader.biBitCount = 1;
561 if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
563 RGBQUAD *rgb = pInfo->bmiColors;
565 pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
566 rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
567 rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
568 rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
570 else
572 RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
574 rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
575 rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
578 /* Create the AND bitmap */
580 if (DoStretch) {
581 if ((hAndBits = CreateBitmap(width, height, 1, 1, NULL))) {
582 HBITMAP hOld;
583 BOOL res = FALSE;
585 if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
586 if (hdcMem) {
587 hOld = SelectObject(hdcMem, hAndBits);
588 res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
589 pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight,
590 xbits, pInfo, DIB_RGB_COLORS, SRCCOPY);
591 SelectObject(hdcMem, hOld);
593 if (!res) { DeleteObject(hAndBits); hAndBits = 0; }
595 } else hAndBits = CreateDIBitmap( screen_dc, &pInfo->bmiHeader,
596 CBM_INIT, xbits, pInfo, DIB_RGB_COLORS );
598 if( !hAndBits ) DeleteObject( hXorBits );
600 HeapFree( GetProcessHeap(), 0, pInfo );
604 if( !hXorBits || !hAndBits )
606 WARN_(cursor)("\tunable to create an icon bitmap.\n");
607 return 0;
610 /* Now create the CURSORICONINFO structure */
611 GetObjectA( hXorBits, sizeof(bmpXor), &bmpXor );
612 GetObjectA( hAndBits, sizeof(bmpAnd), &bmpAnd );
613 sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
614 sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
616 if (hObj) hObj = GlobalReAlloc16( hObj,
617 sizeof(CURSORICONINFO) + sizeXor + sizeAnd, GMEM_MOVEABLE );
618 if (!hObj) hObj = GlobalAlloc16( GMEM_MOVEABLE,
619 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
620 if (hObj)
622 CURSORICONINFO *info;
624 /* Make it owned by the module */
625 if (hInstance) hInstance = GetExePtr(hInstance);
626 FarSetOwner16( hObj, hInstance );
628 info = (CURSORICONINFO *)GlobalLock16( hObj );
629 info->ptHotSpot.x = hotspot.x;
630 info->ptHotSpot.y = hotspot.y;
631 info->nWidth = bmpXor.bmWidth;
632 info->nHeight = bmpXor.bmHeight;
633 info->nWidthBytes = bmpXor.bmWidthBytes;
634 info->bPlanes = bmpXor.bmPlanes;
635 info->bBitsPerPixel = bmpXor.bmBitsPixel;
637 /* Transfer the bitmap bits to the CURSORICONINFO structure */
639 GetBitmapBits( hAndBits, sizeAnd, (char *)(info + 1) );
640 GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
641 GlobalUnlock16( hObj );
644 DeleteObject( hAndBits );
645 DeleteObject( hXorBits );
646 return hObj;
650 /**********************************************************************
651 * CreateIconFromResourceEx (USER.450)
653 * FIXME: not sure about exact parameter types
655 HICON16 WINAPI CreateIconFromResourceEx16( LPBYTE bits, UINT16 cbSize, BOOL16 bIcon,
656 DWORD dwVersion, INT16 width, INT16 height, UINT16 cFlag )
658 return CreateIconFromResourceEx(bits, cbSize, bIcon, dwVersion,
659 width, height, cFlag);
663 /**********************************************************************
664 * CreateIconFromResource (USER32.@)
666 HICON WINAPI CreateIconFromResource( LPBYTE bits, UINT cbSize,
667 BOOL bIcon, DWORD dwVersion)
669 return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
673 /**********************************************************************
674 * CreateIconFromResourceEx (USER32.@)
676 HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
677 BOOL bIcon, DWORD dwVersion,
678 INT width, INT height,
679 UINT cFlag )
681 return CURSORICON_CreateFromResource( 0, 0, bits, cbSize, bIcon, dwVersion,
682 width, height, cFlag );
685 /**********************************************************************
686 * CURSORICON_Load
688 * Load a cursor or icon from resource or file.
690 HGLOBAL CURSORICON_Load( HINSTANCE hInstance, LPCWSTR name,
691 INT width, INT height, INT colors,
692 BOOL fCursor, UINT loadflags )
694 HANDLE handle = 0, h = 0;
695 HANDLE hRsrc;
696 CURSORICONDIR *dir;
697 CURSORICONDIRENTRY *dirEntry;
698 LPBYTE bits;
700 if ( loadflags & LR_LOADFROMFILE ) /* Load from file */
702 LPBYTE *ptr;
703 if (!CURSORICON_SimulateLoadingFromResourceW((LPWSTR)name, fCursor, &dir, &ptr))
704 return 0;
705 if (fCursor)
706 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(dir, width, height, 1);
707 else
708 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(dir, width, height, colors);
709 bits = ptr[dirEntry->wResId-1];
710 h = CURSORICON_CreateFromResource( 0, 0, bits, dirEntry->dwBytesInRes,
711 !fCursor, 0x00030000, width, height, loadflags);
712 HeapFree( GetProcessHeap(), 0, dir );
713 HeapFree( GetProcessHeap(), 0, ptr );
715 else /* Load from resource */
717 HANDLE hGroupRsrc;
718 WORD wResId;
719 DWORD dwBytesInRes;
721 if (!hInstance) /* Load OEM cursor/icon */
723 if (!(hInstance = GetModuleHandleA( "user32.dll" ))) return 0;
726 /* Normalize hInstance (must be uniquely represented for icon cache) */
728 if ( HIWORD( hInstance ) )
729 hInstance = MapHModuleLS( hInstance );
730 else
731 hInstance = GetExePtr( hInstance );
733 /* Get directory resource ID */
735 if (!(hRsrc = FindResourceW( hInstance, name,
736 fCursor ? RT_GROUP_CURSORW : RT_GROUP_ICONW )))
737 return 0;
738 hGroupRsrc = hRsrc;
740 /* Find the best entry in the directory */
742 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
743 if (!(dir = (CURSORICONDIR*)LockResource( handle ))) return 0;
744 if (fCursor)
745 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor( dir,
746 width, height, 1);
747 else
748 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon( dir,
749 width, height, colors );
750 if (!dirEntry) return 0;
751 wResId = dirEntry->wResId;
752 dwBytesInRes = dirEntry->dwBytesInRes;
753 FreeResource( handle );
755 /* Load the resource */
757 if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
758 fCursor ? RT_CURSORW : RT_ICONW ))) return 0;
760 /* If shared icon, check whether it was already loaded */
761 if ( (loadflags & LR_SHARED)
762 && (h = CURSORICON_FindSharedIcon( hInstance, hRsrc ) ) != 0 )
763 return h;
765 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
766 bits = (LPBYTE)LockResource( handle );
767 h = CURSORICON_CreateFromResource( 0, 0, bits, dwBytesInRes,
768 !fCursor, 0x00030000, width, height, loadflags);
769 FreeResource( handle );
771 /* If shared icon, add to icon cache */
773 if ( h && (loadflags & LR_SHARED) )
774 CURSORICON_AddSharedIcon( hInstance, hRsrc, hGroupRsrc, h );
777 return h;
780 /***********************************************************************
781 * CURSORICON_Copy
783 * Make a copy of a cursor or icon.
785 static HGLOBAL16 CURSORICON_Copy( HINSTANCE16 hInstance, HGLOBAL16 handle )
787 char *ptrOld, *ptrNew;
788 int size;
789 HGLOBAL16 hNew;
791 if (!(ptrOld = (char *)GlobalLock16( handle ))) return 0;
792 if (hInstance && !(hInstance = GetExePtr( hInstance ))) return 0;
793 size = GlobalSize16( handle );
794 hNew = GlobalAlloc16( GMEM_MOVEABLE, size );
795 FarSetOwner16( hNew, hInstance );
796 ptrNew = (char *)GlobalLock16( hNew );
797 memcpy( ptrNew, ptrOld, size );
798 GlobalUnlock16( handle );
799 GlobalUnlock16( hNew );
800 return hNew;
803 /*************************************************************************
804 * CURSORICON_ExtCopy
806 * Copies an Image from the Cache if LR_COPYFROMRESOURCE is specified
808 * PARAMS
809 * Handle [I] handle to an Image
810 * nType [I] Type of Handle (IMAGE_CURSOR | IMAGE_ICON)
811 * iDesiredCX [I] The Desired width of the Image
812 * iDesiredCY [I] The desired height of the Image
813 * nFlags [I] The flags from CopyImage
815 * RETURNS
816 * Success: The new handle of the Image
818 * NOTES
819 * LR_COPYDELETEORG and LR_MONOCHROME are currently not implemented.
820 * LR_MONOCHROME should be implemented by CURSORICON_CreateFromResource.
821 * LR_COPYFROMRESOURCE will only work if the Image is in the Cache.
826 HGLOBAL CURSORICON_ExtCopy(HGLOBAL Handle, UINT nType,
827 INT iDesiredCX, INT iDesiredCY,
828 UINT nFlags)
830 HGLOBAL16 hNew=0;
832 TRACE_(icon)("Handle %u, uType %u, iDesiredCX %i, iDesiredCY %i, nFlags %u\n",
833 Handle, nType, iDesiredCX, iDesiredCY, nFlags);
835 if(Handle == 0)
837 return 0;
840 /* Best Fit or Monochrome */
841 if( (nFlags & LR_COPYFROMRESOURCE
842 && (iDesiredCX > 0 || iDesiredCY > 0))
843 || nFlags & LR_MONOCHROME)
845 ICONCACHE* pIconCache = CURSORICON_FindCache(Handle);
847 /* Not Found in Cache, then do a straight copy
849 if(pIconCache == NULL)
851 hNew = CURSORICON_Copy(0, Handle);
852 if(nFlags & LR_COPYFROMRESOURCE)
854 TRACE_(icon)("LR_COPYFROMRESOURCE: Failed to load from cache\n");
857 else
859 int iTargetCY = iDesiredCY, iTargetCX = iDesiredCX;
860 LPBYTE pBits;
861 HANDLE hMem;
862 HRSRC hRsrc;
863 DWORD dwBytesInRes;
864 WORD wResId;
865 CURSORICONDIR *pDir;
866 CURSORICONDIRENTRY *pDirEntry;
867 BOOL bIsIcon = (nType == IMAGE_ICON);
869 /* Completing iDesiredCX CY for Monochrome Bitmaps if needed
871 if(((nFlags & LR_MONOCHROME) && !(nFlags & LR_COPYFROMRESOURCE))
872 || (iDesiredCX == 0 && iDesiredCY == 0))
874 iDesiredCY = GetSystemMetrics(bIsIcon ?
875 SM_CYICON : SM_CYCURSOR);
876 iDesiredCX = GetSystemMetrics(bIsIcon ?
877 SM_CXICON : SM_CXCURSOR);
880 /* Retrieve the CURSORICONDIRENTRY
882 if (!(hMem = LoadResource( pIconCache->hModule ,
883 pIconCache->hGroupRsrc)))
885 return 0;
887 if (!(pDir = (CURSORICONDIR*)LockResource( hMem )))
889 return 0;
892 /* Find Best Fit
894 if(bIsIcon)
896 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(
897 pDir, iDesiredCX, iDesiredCY, 256);
899 else
901 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(
902 pDir, iDesiredCX, iDesiredCY, 1);
905 wResId = pDirEntry->wResId;
906 dwBytesInRes = pDirEntry->dwBytesInRes;
907 FreeResource(hMem);
909 TRACE_(icon)("ResID %u, BytesInRes %lu, Width %d, Height %d DX %d, DY %d\n",
910 wResId, dwBytesInRes, pDirEntry->ResInfo.icon.bWidth,
911 pDirEntry->ResInfo.icon.bHeight, iDesiredCX, iDesiredCY);
913 /* Get the Best Fit
915 if (!(hRsrc = FindResourceW(pIconCache->hModule ,
916 MAKEINTRESOURCEW(wResId), bIsIcon ? RT_ICONW : RT_CURSORW)))
918 return 0;
920 if (!(hMem = LoadResource( pIconCache->hModule , hRsrc )))
922 return 0;
925 pBits = (LPBYTE)LockResource( hMem );
927 if(nFlags & LR_DEFAULTSIZE)
929 iTargetCY = GetSystemMetrics(SM_CYICON);
930 iTargetCX = GetSystemMetrics(SM_CXICON);
933 /* Create a New Icon with the proper dimension
935 hNew = CURSORICON_CreateFromResource( 0, 0, pBits, dwBytesInRes,
936 bIsIcon, 0x00030000, iTargetCX, iTargetCY, nFlags);
937 FreeResource(hMem);
940 else hNew = CURSORICON_Copy(0, Handle);
941 return hNew;
944 /***********************************************************************
945 * CURSORICON_IconToCursor
947 * Converts bitmap to mono and truncates if icon is too large (should
948 * probably do StretchBlt() instead).
950 HCURSOR16 CURSORICON_IconToCursor(HICON16 hIcon, BOOL bSemiTransparent)
952 HCURSOR16 hRet = 0;
953 CURSORICONINFO *pIcon = NULL;
955 if(hIcon)
956 if (!(pIcon = (CURSORICONINFO*)GlobalLock16( hIcon ))) return FALSE;
957 if (pIcon->bPlanes * pIcon->bBitsPerPixel == 1)
959 hRet = CURSORICON_Copy( 0, hIcon );
962 pIcon = GlobalLock16(hRet);
964 pIcon->ptHotSpot.x = pIcon->ptHotSpot.y = 15;
966 GlobalUnlock16(hRet);
968 else
970 BYTE pAndBits[128];
971 BYTE pXorBits[128];
972 int maxx, maxy, ix, iy, bpp = pIcon->bBitsPerPixel;
973 BYTE* psPtr, *pxbPtr = pXorBits;
974 unsigned xor_width, and_width, val_base = 0xffffffff >> (32 - bpp);
975 BYTE* pbc = NULL;
977 CURSORICONINFO cI;
979 TRACE_(icon)("[%04x] %ix%i %ibpp (bogus %ibps)\n",
980 hIcon, pIcon->nWidth, pIcon->nHeight, pIcon->bBitsPerPixel, pIcon->nWidthBytes );
982 xor_width = BITMAP_GetWidthBytes( pIcon->nWidth, bpp );
983 and_width = BITMAP_GetWidthBytes( pIcon->nWidth, 1 );
984 psPtr = (BYTE *)(pIcon + 1) + pIcon->nHeight * and_width;
986 memset(pXorBits, 0, 128);
987 cI.bBitsPerPixel = 1; cI.bPlanes = 1;
988 cI.ptHotSpot.x = cI.ptHotSpot.y = 15;
989 cI.nWidth = 32; cI.nHeight = 32;
990 cI.nWidthBytes = 4; /* 32x1bpp */
992 maxx = (pIcon->nWidth > 32) ? 32 : pIcon->nWidth;
993 maxy = (pIcon->nHeight > 32) ? 32 : pIcon->nHeight;
995 for( iy = 0; iy < maxy; iy++ )
997 unsigned shift = iy % 2;
999 memcpy( pAndBits + iy * 4, (BYTE *)(pIcon + 1) + iy * and_width,
1000 (and_width > 4) ? 4 : and_width );
1001 for( ix = 0; ix < maxx; ix++ )
1003 if( bSemiTransparent && ((ix+shift)%2) )
1005 /* set AND bit, XOR bit stays 0 */
1007 pbc = pAndBits + iy * 4 + ix/8;
1008 *pbc |= 0x80 >> (ix%8);
1010 else
1012 /* keep AND bit, set XOR bit */
1014 unsigned *psc = (unsigned*)(psPtr + (ix * bpp)/8);
1015 unsigned val = ((*psc) >> (ix * bpp)%8) & val_base;
1016 if(!PALETTE_Driver->pIsDark(val))
1018 pbc = pxbPtr + ix/8;
1019 *pbc |= 0x80 >> (ix%8);
1023 psPtr += xor_width;
1024 pxbPtr += 4;
1027 hRet = CreateCursorIconIndirect16( 0 , &cI, pAndBits, pXorBits);
1029 if( !hRet ) /* fall back on default drag cursor */
1030 hRet = CURSORICON_Copy( 0 ,
1031 CURSORICON_Load(0,MAKEINTRESOURCEW(OCR_DRAGOBJECT),
1032 GetSystemMetrics(SM_CXCURSOR),
1033 GetSystemMetrics(SM_CYCURSOR), 1, TRUE, 0) );
1036 return hRet;
1040 /***********************************************************************
1041 * LoadCursor (USER.173)
1043 HCURSOR16 WINAPI LoadCursor16( HINSTANCE16 hInstance, LPCSTR name )
1045 return LoadCursorA( hInstance, name );
1049 /***********************************************************************
1050 * LoadIcon (USER.174)
1052 HICON16 WINAPI LoadIcon16( HINSTANCE16 hInstance, LPCSTR name )
1054 return LoadIconA( hInstance, name );
1058 /***********************************************************************
1059 * CreateCursor (USER.406)
1061 HCURSOR16 WINAPI CreateCursor16( HINSTANCE16 hInstance,
1062 INT16 xHotSpot, INT16 yHotSpot,
1063 INT16 nWidth, INT16 nHeight,
1064 LPCVOID lpANDbits, LPCVOID lpXORbits )
1066 CURSORICONINFO info;
1068 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1069 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1071 info.ptHotSpot.x = xHotSpot;
1072 info.ptHotSpot.y = yHotSpot;
1073 info.nWidth = nWidth;
1074 info.nHeight = nHeight;
1075 info.nWidthBytes = 0;
1076 info.bPlanes = 1;
1077 info.bBitsPerPixel = 1;
1079 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1083 /***********************************************************************
1084 * CreateCursor (USER32.@)
1086 HCURSOR WINAPI CreateCursor( HINSTANCE hInstance,
1087 INT xHotSpot, INT yHotSpot,
1088 INT nWidth, INT nHeight,
1089 LPCVOID lpANDbits, LPCVOID lpXORbits )
1091 CURSORICONINFO info;
1093 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1094 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1096 info.ptHotSpot.x = xHotSpot;
1097 info.ptHotSpot.y = yHotSpot;
1098 info.nWidth = nWidth;
1099 info.nHeight = nHeight;
1100 info.nWidthBytes = 0;
1101 info.bPlanes = 1;
1102 info.bBitsPerPixel = 1;
1104 return CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
1108 /***********************************************************************
1109 * CreateIcon (USER.407)
1111 HICON16 WINAPI CreateIcon16( HINSTANCE16 hInstance, INT16 nWidth,
1112 INT16 nHeight, BYTE bPlanes, BYTE bBitsPixel,
1113 LPCVOID lpANDbits, LPCVOID lpXORbits )
1115 CURSORICONINFO info;
1117 TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1118 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1120 info.ptHotSpot.x = ICON_HOTSPOT;
1121 info.ptHotSpot.y = ICON_HOTSPOT;
1122 info.nWidth = nWidth;
1123 info.nHeight = nHeight;
1124 info.nWidthBytes = 0;
1125 info.bPlanes = bPlanes;
1126 info.bBitsPerPixel = bBitsPixel;
1128 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1132 /***********************************************************************
1133 * CreateIcon (USER32.@)
1135 * Creates an icon based on the specified bitmaps. The bitmaps must be
1136 * provided in a device dependent format and will be resized to
1137 * (SM_CXICON,SM_CYICON) and depth converted to match the screen's color
1138 * depth. The provided bitmaps must be top-down bitmaps.
1139 * Although Windows does not support 15bpp(*) this API must support it
1140 * for Winelib applications.
1142 * (*) Windows does not support 15bpp but it supports the 555 RGB 16bpp
1143 * format!
1145 * BUGS
1147 * - The provided bitmaps are not resized!
1148 * - The documentation says the lpXORbits bitmap must be in a device
1149 * dependent format. But we must still resize it and perform depth
1150 * conversions if necessary.
1151 * - I'm a bit unsure about the how the 'device dependent format' thing works.
1152 * I did some tests on windows and found that if you provide a 16bpp bitmap
1153 * in lpXORbits, then its format but be 565 RGB if the screen's bit depth
1154 * is 16bpp but it must be 555 RGB if the screen's bit depth is anything
1155 * else. I don't know if this is part of the GDI specs or if this is a
1156 * quirk of the graphics card driver.
1157 * - You may think that we check whether the bit depths match or not
1158 * as an optimization. But the truth is that the conversion using
1159 * CreateDIBitmap does not work for some bit depth (e.g. 8bpp) and I have
1160 * no idea why.
1161 * - I'm pretty sure that all the things we do in CreateIcon should
1162 * also be done in CreateIconIndirect...
1164 HICON WINAPI CreateIcon(
1165 HINSTANCE hInstance, /* [in] the application's hInstance, currently unused */
1166 INT nWidth, /* [in] the width of the provided bitmaps */
1167 INT nHeight, /* [in] the height of the provided bitmaps */
1168 BYTE bPlanes, /* [in] the number of planes in the provided bitmaps */
1169 BYTE bBitsPixel, /* [in] the number of bits per pixel of the lpXORbits bitmap */
1170 LPCVOID lpANDbits, /* [in] a monochrome bitmap representing the icon's mask */
1171 LPCVOID lpXORbits) /* [in] 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 * ShowCursor (USER.71)
1474 INT16 WINAPI ShowCursor16( BOOL16 bShow )
1476 return ShowCursor( bShow );
1480 /***********************************************************************
1481 * ShowCursor (USER32.@)
1483 INT WINAPI ShowCursor( BOOL bShow )
1485 TRACE_(cursor)("%d, count=%d\n",
1486 bShow, CURSOR_ShowCount );
1488 if (bShow)
1490 if (++CURSOR_ShowCount == 0) /* Show it */
1492 USER_Driver.pSetCursor( (CURSORICONINFO*)GlobalLock16( hActiveCursor ) );
1493 GlobalUnlock16( hActiveCursor );
1496 else
1498 if (--CURSOR_ShowCount == -1) /* Hide it */
1499 USER_Driver.pSetCursor( NULL );
1501 return CURSOR_ShowCount;
1505 /***********************************************************************
1506 * GetCursor (USER.247)
1508 HCURSOR16 WINAPI GetCursor16(void)
1510 return hActiveCursor;
1514 /***********************************************************************
1515 * GetCursor (USER32.@)
1517 HCURSOR WINAPI GetCursor(void)
1519 return hActiveCursor;
1523 /***********************************************************************
1524 * ClipCursor (USER.16)
1526 BOOL16 WINAPI ClipCursor16( const RECT16 *rect )
1528 if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1529 else CONV_RECT16TO32( rect, &CURSOR_ClipRect );
1530 return TRUE;
1534 /***********************************************************************
1535 * ClipCursor (USER32.@)
1537 BOOL WINAPI ClipCursor( const RECT *rect )
1539 if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1540 else CopyRect( &CURSOR_ClipRect, rect );
1541 return TRUE;
1545 /***********************************************************************
1546 * GetClipCursor (USER.309)
1548 void WINAPI GetClipCursor16( RECT16 *rect )
1550 if (rect) CONV_RECT32TO16( &CURSOR_ClipRect, rect );
1554 /***********************************************************************
1555 * GetClipCursor (USER32.@)
1557 BOOL WINAPI GetClipCursor( RECT *rect )
1559 if (rect)
1561 CopyRect( rect, &CURSOR_ClipRect );
1562 return TRUE;
1564 return FALSE;
1567 /**********************************************************************
1568 * LookupIconIdFromDirectoryEx (USER.364)
1570 * FIXME: exact parameter sizes
1572 INT16 WINAPI LookupIconIdFromDirectoryEx16( LPBYTE xdir, BOOL16 bIcon,
1573 INT16 width, INT16 height, UINT16 cFlag )
1575 CURSORICONDIR *dir = (CURSORICONDIR*)xdir;
1576 UINT16 retVal = 0;
1577 if( dir && !dir->idReserved && (dir->idType & 3) )
1579 CURSORICONDIRENTRY* entry;
1580 HDC hdc;
1581 UINT palEnts;
1582 int colors;
1583 hdc = GetDC(0);
1584 palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
1585 if (palEnts == 0)
1586 palEnts = 256;
1587 colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
1589 ReleaseDC(0, hdc);
1591 if( bIcon )
1592 entry = CURSORICON_FindBestIcon( dir, width, height, colors );
1593 else
1594 entry = CURSORICON_FindBestCursor( dir, width, height, 1);
1596 if( entry ) retVal = entry->wResId;
1598 else WARN_(cursor)("invalid resource directory\n");
1599 return retVal;
1602 /**********************************************************************
1603 * LookupIconIdFromDirectoryEx (USER32.@)
1605 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE dir, BOOL bIcon,
1606 INT width, INT height, UINT cFlag )
1608 return LookupIconIdFromDirectoryEx16( dir, bIcon, width, height, cFlag );
1611 /**********************************************************************
1612 * LookupIconIdFromDirectory (USER.?)
1614 INT16 WINAPI LookupIconIdFromDirectory16( LPBYTE dir, BOOL16 bIcon )
1616 return LookupIconIdFromDirectoryEx16( dir, bIcon,
1617 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1618 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1621 /**********************************************************************
1622 * LookupIconIdFromDirectory (USER32.@)
1624 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1626 return LookupIconIdFromDirectoryEx( dir, bIcon,
1627 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1628 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1631 /**********************************************************************
1632 * GetIconID (USER.455)
1634 WORD WINAPI GetIconID16( HGLOBAL16 hResource, DWORD resType )
1636 LPBYTE lpDir = (LPBYTE)GlobalLock16(hResource);
1638 TRACE_(cursor)("hRes=%04x, entries=%i\n",
1639 hResource, lpDir ? ((CURSORICONDIR*)lpDir)->idCount : 0);
1641 switch(resType)
1643 case RT_CURSOR16:
1644 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, FALSE,
1645 GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1646 case RT_ICON16:
1647 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, TRUE,
1648 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0 );
1649 default:
1650 WARN_(cursor)("invalid res type %ld\n", resType );
1652 return 0;
1655 /**********************************************************************
1656 * LoadCursorIconHandler (USER.336)
1658 * Supposed to load resources of Windows 2.x applications.
1660 HGLOBAL16 WINAPI LoadCursorIconHandler16( HGLOBAL16 hResource, HMODULE16 hModule, HRSRC16 hRsrc )
1662 FIXME_(cursor)("(%04x,%04x,%04x): old 2.x resources are not supported!\n",
1663 hResource, hModule, hRsrc);
1664 return (HGLOBAL16)0;
1667 /**********************************************************************
1668 * LoadDIBIconHandler (USER.357)
1670 * RT_ICON resource loader, installed by USER_SignalProc when module
1671 * is initialized.
1673 HGLOBAL16 WINAPI LoadDIBIconHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1675 /* If hResource is zero we must allocate a new memory block, if it's
1676 * non-zero but GlobalLock() returns NULL then it was discarded and
1677 * we have to recommit some memory, otherwise we just need to check
1678 * the block size. See LoadProc() in 16-bit SDK for more.
1681 hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1682 if( hMemObj )
1684 LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1685 hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1686 SizeofResource16(hModule, hRsrc), TRUE, 0x00030000,
1687 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR );
1689 return hMemObj;
1692 /**********************************************************************
1693 * LoadDIBCursorHandler (USER.356)
1695 * RT_CURSOR resource loader. Same as above.
1697 HGLOBAL16 WINAPI LoadDIBCursorHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1699 hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1700 if( hMemObj )
1702 LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1703 hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1704 SizeofResource16(hModule, hRsrc), FALSE, 0x00030000,
1705 GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1707 return hMemObj;
1710 /**********************************************************************
1711 * LoadIconHandler (USER.456)
1713 HICON16 WINAPI LoadIconHandler16( HGLOBAL16 hResource, BOOL16 bNew )
1715 LPBYTE bits = (LPBYTE)LockResource16( hResource );
1717 TRACE_(cursor)("hRes=%04x\n",hResource);
1719 return CURSORICON_CreateFromResource( 0, 0, bits, 0, TRUE,
1720 bNew ? 0x00030000 : 0x00020000, 0, 0, LR_DEFAULTCOLOR );
1723 /***********************************************************************
1724 * LoadCursorW (USER32.@)
1726 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
1728 return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0,
1729 LR_SHARED | LR_DEFAULTSIZE );
1732 /***********************************************************************
1733 * LoadCursorA (USER32.@)
1735 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
1737 return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0,
1738 LR_SHARED | LR_DEFAULTSIZE );
1741 /***********************************************************************
1742 * LoadCursorFromFileW (USER32.@)
1744 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
1746 return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0,
1747 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1750 /***********************************************************************
1751 * LoadCursorFromFileA (USER32.@)
1753 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
1755 return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0,
1756 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1759 /***********************************************************************
1760 * LoadIconW (USER32.@)
1762 HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
1764 return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0,
1765 LR_SHARED | LR_DEFAULTSIZE );
1768 /***********************************************************************
1769 * LoadIconA (USER32.@)
1771 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
1773 return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0,
1774 LR_SHARED | LR_DEFAULTSIZE );
1777 /**********************************************************************
1778 * GetIconInfo (USER.395)
1780 BOOL16 WINAPI GetIconInfo16(HICON16 hIcon,LPICONINFO16 iconinfo)
1782 ICONINFO ii32;
1783 BOOL16 ret = GetIconInfo((HICON)hIcon, &ii32);
1785 iconinfo->fIcon = ii32.fIcon;
1786 iconinfo->xHotspot = ii32.xHotspot;
1787 iconinfo->yHotspot = ii32.yHotspot;
1788 iconinfo->hbmMask = ii32.hbmMask;
1789 iconinfo->hbmColor = ii32.hbmColor;
1790 return ret;
1793 /**********************************************************************
1794 * GetIconInfo (USER32.@)
1796 BOOL WINAPI GetIconInfo(HICON hIcon,PICONINFO iconinfo) {
1797 CURSORICONINFO *ciconinfo;
1799 ciconinfo = GlobalLock16(hIcon);
1800 if (!ciconinfo)
1801 return FALSE;
1803 if ( (ciconinfo->ptHotSpot.x == ICON_HOTSPOT) &&
1804 (ciconinfo->ptHotSpot.y == ICON_HOTSPOT) )
1806 iconinfo->fIcon = TRUE;
1807 iconinfo->xHotspot = ciconinfo->nWidth / 2;
1808 iconinfo->yHotspot = ciconinfo->nHeight / 2;
1810 else
1812 iconinfo->fIcon = FALSE;
1813 iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
1814 iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
1817 iconinfo->hbmColor = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1818 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
1819 (char *)(ciconinfo + 1)
1820 + ciconinfo->nHeight *
1821 BITMAP_GetWidthBytes (ciconinfo->nWidth,1) );
1822 iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1823 1, 1, (char *)(ciconinfo + 1));
1825 GlobalUnlock16(hIcon);
1827 return TRUE;
1830 /**********************************************************************
1831 * CreateIconIndirect (USER32.@)
1833 HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
1835 BITMAP bmpXor,bmpAnd;
1836 HICON hObj;
1837 int sizeXor,sizeAnd;
1839 GetObjectA( iconinfo->hbmColor, sizeof(bmpXor), &bmpXor );
1840 GetObjectA( iconinfo->hbmMask, sizeof(bmpAnd), &bmpAnd );
1842 sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
1843 sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
1845 hObj = GlobalAlloc16( GMEM_MOVEABLE,
1846 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
1847 if (hObj)
1849 CURSORICONINFO *info;
1851 info = (CURSORICONINFO *)GlobalLock16( hObj );
1853 /* If we are creating an icon, the hotspot is unused */
1854 if (iconinfo->fIcon)
1856 info->ptHotSpot.x = ICON_HOTSPOT;
1857 info->ptHotSpot.y = ICON_HOTSPOT;
1859 else
1861 info->ptHotSpot.x = iconinfo->xHotspot;
1862 info->ptHotSpot.y = iconinfo->yHotspot;
1865 info->nWidth = bmpXor.bmWidth;
1866 info->nHeight = bmpXor.bmHeight;
1867 info->nWidthBytes = bmpXor.bmWidthBytes;
1868 info->bPlanes = bmpXor.bmPlanes;
1869 info->bBitsPerPixel = bmpXor.bmBitsPixel;
1871 /* Transfer the bitmap bits to the CURSORICONINFO structure */
1873 GetBitmapBits( iconinfo->hbmMask ,sizeAnd,(char*)(info + 1) );
1874 GetBitmapBits( iconinfo->hbmColor,sizeXor,(char*)(info + 1) +sizeAnd);
1875 GlobalUnlock16( hObj );
1877 return hObj;
1881 /**********************************************************************
1882 * DrawIconEx (USER.394)
1884 BOOL16 WINAPI DrawIconEx16 (HDC16 hdc, INT16 xLeft, INT16 yTop, HICON16 hIcon,
1885 INT16 cxWidth, INT16 cyWidth, UINT16 istep,
1886 HBRUSH16 hbr, UINT16 flags)
1888 return DrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
1889 istep, hbr, flags);
1893 /******************************************************************************
1894 * DrawIconEx (USER32.@) Draws an icon or cursor on device context
1896 * NOTES
1897 * Why is this using SM_CXICON instead of SM_CXCURSOR?
1899 * PARAMS
1900 * hdc [I] Handle to device context
1901 * x0 [I] X coordinate of upper left corner
1902 * y0 [I] Y coordinate of upper left corner
1903 * hIcon [I] Handle to icon to draw
1904 * cxWidth [I] Width of icon
1905 * cyWidth [I] Height of icon
1906 * istep [I] Index of frame in animated cursor
1907 * hbr [I] Handle to background brush
1908 * flags [I] Icon-drawing flags
1910 * RETURNS
1911 * Success: TRUE
1912 * Failure: FALSE
1914 BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
1915 INT cxWidth, INT cyWidth, UINT istep,
1916 HBRUSH hbr, UINT flags )
1918 CURSORICONINFO *ptr = (CURSORICONINFO *)GlobalLock16 (hIcon);
1919 HDC hDC_off = 0, hMemDC = CreateCompatibleDC (hdc);
1920 BOOL result = FALSE, DoOffscreen;
1921 HBITMAP hB_off = 0, hOld = 0;
1923 if (!ptr) return FALSE;
1924 TRACE_(icon)("(hdc=%x,pos=%d.%d,hicon=%x,extend=%d.%d,istep=%d,br=%x,flags=0x%08x)\n",
1925 hdc,x0,y0,hIcon,cxWidth,cyWidth,istep,hbr,flags
1928 if (istep)
1929 FIXME_(icon)("Ignoring istep=%d\n", istep);
1930 if (flags & DI_COMPAT)
1931 FIXME_(icon)("Ignoring flag DI_COMPAT\n");
1933 if (!flags) {
1934 FIXME_(icon)("no flags set? setting to DI_NORMAL\n");
1935 flags = DI_NORMAL;
1938 /* Calculate the size of the destination image. */
1939 if (cxWidth == 0)
1941 if (flags & DI_DEFAULTSIZE)
1942 cxWidth = GetSystemMetrics (SM_CXICON);
1943 else
1944 cxWidth = ptr->nWidth;
1946 if (cyWidth == 0)
1948 if (flags & DI_DEFAULTSIZE)
1949 cyWidth = GetSystemMetrics (SM_CYICON);
1950 else
1951 cyWidth = ptr->nHeight;
1954 DoOffscreen = (GetObjectType( hbr ) == OBJ_BRUSH);
1956 if (DoOffscreen) {
1957 RECT r;
1959 r.left = 0;
1960 r.top = 0;
1961 r.right = cxWidth;
1962 r.bottom = cxWidth;
1964 hDC_off = CreateCompatibleDC(hdc);
1965 hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth);
1966 if (hDC_off && hB_off) {
1967 hOld = SelectObject(hDC_off, hB_off);
1968 FillRect(hDC_off, &r, hbr);
1972 if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
1974 HBITMAP hXorBits, hAndBits;
1975 COLORREF oldFg, oldBg;
1976 INT nStretchMode;
1978 nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
1980 hXorBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1981 ptr->bPlanes, ptr->bBitsPerPixel,
1982 (char *)(ptr + 1)
1983 + ptr->nHeight *
1984 BITMAP_GetWidthBytes(ptr->nWidth,1) );
1985 hAndBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1986 1, 1, (char *)(ptr+1) );
1987 oldFg = SetTextColor( hdc, RGB(0,0,0) );
1988 oldBg = SetBkColor( hdc, RGB(255,255,255) );
1990 if (hXorBits && hAndBits)
1992 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1993 if (flags & DI_MASK)
1995 if (DoOffscreen)
1996 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1997 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1998 else
1999 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
2000 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
2002 SelectObject( hMemDC, hXorBits );
2003 if (flags & DI_IMAGE)
2005 if (DoOffscreen)
2006 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
2007 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
2008 else
2009 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
2010 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
2012 SelectObject( hMemDC, hBitTemp );
2013 result = TRUE;
2016 SetTextColor( hdc, oldFg );
2017 SetBkColor( hdc, oldBg );
2018 if (hXorBits) DeleteObject( hXorBits );
2019 if (hAndBits) DeleteObject( hAndBits );
2020 SetStretchBltMode (hdc, nStretchMode);
2021 if (DoOffscreen) {
2022 BitBlt(hdc, x0, y0, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
2023 SelectObject(hDC_off, hOld);
2026 if (hMemDC) DeleteDC( hMemDC );
2027 if (hDC_off) DeleteDC(hDC_off);
2028 if (hB_off) DeleteObject(hB_off);
2029 GlobalUnlock16( hIcon );
2030 return result;
2033 /***********************************************************************
2034 * DIB_FixColorsToLoadflags
2036 * Change color table entries when LR_LOADTRANSPARENT or LR_LOADMAP3DCOLORS
2037 * are in loadflags
2039 static void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags, BYTE pix)
2041 int colors;
2042 COLORREF c_W, c_S, c_F, c_L, c_C;
2043 int incr,i;
2044 RGBQUAD *ptr;
2046 if (bmi->bmiHeader.biBitCount > 8) return;
2047 if (bmi->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)) incr = 4;
2048 else if (bmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) incr = 3;
2049 else {
2050 WARN_(resource)("Wrong bitmap header size!\n");
2051 return;
2053 colors = bmi->bmiHeader.biClrUsed;
2054 if (!colors && (bmi->bmiHeader.biBitCount <= 8))
2055 colors = 1 << bmi->bmiHeader.biBitCount;
2056 c_W = GetSysColor(COLOR_WINDOW);
2057 c_S = GetSysColor(COLOR_3DSHADOW);
2058 c_F = GetSysColor(COLOR_3DFACE);
2059 c_L = GetSysColor(COLOR_3DLIGHT);
2060 if (loadflags & LR_LOADTRANSPARENT) {
2061 switch (bmi->bmiHeader.biBitCount) {
2062 case 1: pix = pix >> 7; break;
2063 case 4: pix = pix >> 4; break;
2064 case 8: break;
2065 default:
2066 WARN_(resource)("(%d): Unsupported depth\n", bmi->bmiHeader.biBitCount);
2067 return;
2069 if (pix >= colors) {
2070 WARN_(resource)("pixel has color index greater than biClrUsed!\n");
2071 return;
2073 if (loadflags & LR_LOADMAP3DCOLORS) c_W = c_F;
2074 ptr = (RGBQUAD*)((char*)bmi->bmiColors+pix*incr);
2075 ptr->rgbBlue = GetBValue(c_W);
2076 ptr->rgbGreen = GetGValue(c_W);
2077 ptr->rgbRed = GetRValue(c_W);
2079 if (loadflags & LR_LOADMAP3DCOLORS)
2080 for (i=0; i<colors; i++) {
2081 ptr = (RGBQUAD*)((char*)bmi->bmiColors+i*incr);
2082 c_C = RGB(ptr->rgbRed, ptr->rgbGreen, ptr->rgbBlue);
2083 if (c_C == RGB(128, 128, 128)) {
2084 ptr->rgbRed = GetRValue(c_S);
2085 ptr->rgbGreen = GetGValue(c_S);
2086 ptr->rgbBlue = GetBValue(c_S);
2087 } else if (c_C == RGB(192, 192, 192)) {
2088 ptr->rgbRed = GetRValue(c_F);
2089 ptr->rgbGreen = GetGValue(c_F);
2090 ptr->rgbBlue = GetBValue(c_F);
2091 } else if (c_C == RGB(223, 223, 223)) {
2092 ptr->rgbRed = GetRValue(c_L);
2093 ptr->rgbGreen = GetGValue(c_L);
2094 ptr->rgbBlue = GetBValue(c_L);
2100 /**********************************************************************
2101 * BITMAP_Load
2103 static HBITMAP BITMAP_Load( HINSTANCE instance,LPCWSTR name, UINT loadflags )
2105 HBITMAP hbitmap = 0;
2106 HRSRC hRsrc;
2107 HGLOBAL handle;
2108 char *ptr = NULL;
2109 BITMAPINFO *info, *fix_info=NULL;
2110 HGLOBAL hFix;
2111 int size;
2113 if (!(loadflags & LR_LOADFROMFILE)) {
2114 if (!instance) /* OEM bitmap */
2116 if (HIWORD((int)name)) return 0;
2117 return USER_Driver.pLoadOEMResource( LOWORD((int)name), OEM_BITMAP );
2120 if (!(hRsrc = FindResourceW( instance, name, RT_BITMAPW ))) return 0;
2121 if (!(handle = LoadResource( instance, hRsrc ))) return 0;
2123 if ((info = (BITMAPINFO *)LockResource( handle )) == NULL) return 0;
2125 else
2127 if (!(ptr = map_fileW( name ))) return 0;
2128 info = (BITMAPINFO *)(ptr + sizeof(BITMAPFILEHEADER));
2130 size = DIB_BitmapInfoSize(info, DIB_RGB_COLORS);
2131 if ((hFix = GlobalAlloc(0, size))) fix_info=GlobalLock(hFix);
2132 if (fix_info) {
2133 BYTE pix;
2135 memcpy(fix_info, info, size);
2136 pix = *((LPBYTE)info+DIB_BitmapInfoSize(info, DIB_RGB_COLORS));
2137 DIB_FixColorsToLoadflags(fix_info, loadflags, pix);
2138 if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
2139 if (screen_dc)
2141 char *bits = (char *)info + size;
2142 if (loadflags & LR_CREATEDIBSECTION) {
2143 DIBSECTION dib;
2144 hbitmap = CreateDIBSection(screen_dc, fix_info, DIB_RGB_COLORS, NULL, 0, 0);
2145 GetObjectA(hbitmap, sizeof(DIBSECTION), &dib);
2146 SetDIBits(screen_dc, hbitmap, 0, dib.dsBm.bmHeight, bits, info,
2147 DIB_RGB_COLORS);
2149 else {
2150 hbitmap = CreateDIBitmap( screen_dc, &fix_info->bmiHeader, CBM_INIT,
2151 bits, fix_info, DIB_RGB_COLORS );
2154 GlobalUnlock(hFix);
2155 GlobalFree(hFix);
2157 if (loadflags & LR_LOADFROMFILE) UnmapViewOfFile( ptr );
2158 return hbitmap;
2162 /***********************************************************************
2163 * LoadImage (USER.389)
2166 HANDLE16 WINAPI LoadImage16( HINSTANCE16 hinst, LPCSTR name, UINT16 type,
2167 INT16 desiredx, INT16 desiredy, UINT16 loadflags)
2169 return LoadImageA( hinst, name, type, desiredx, desiredy, loadflags );
2172 /**********************************************************************
2173 * LoadImageA (USER32.@)
2175 * FIXME: implementation lacks some features, see LR_ defines in winuser.h
2178 /* filter for page-fault exceptions */
2179 static WINE_EXCEPTION_FILTER(page_fault)
2181 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
2182 return EXCEPTION_EXECUTE_HANDLER;
2183 return EXCEPTION_CONTINUE_SEARCH;
2186 HANDLE WINAPI LoadImageA( HINSTANCE hinst, LPCSTR name, UINT type,
2187 INT desiredx, INT desiredy, UINT loadflags)
2189 HANDLE res;
2190 LPWSTR u_name;
2192 __TRY {
2193 if (HIWORD(name)) u_name = HEAP_strdupAtoW(GetProcessHeap(), 0, name);
2194 else u_name=(LPWSTR)name;
2196 __EXCEPT(page_fault) {
2197 SetLastError( ERROR_INVALID_PARAMETER );
2198 return 0;
2200 __ENDTRY
2201 res = LoadImageW(hinst, u_name, type, desiredx, desiredy, loadflags);
2202 if (HIWORD(name)) HeapFree(GetProcessHeap(), 0, u_name);
2203 return res;
2207 /******************************************************************************
2208 * LoadImageW (USER32.@) Loads an icon, cursor, or bitmap
2210 * PARAMS
2211 * hinst [I] Handle of instance that contains image
2212 * name [I] Name of image
2213 * type [I] Type of image
2214 * desiredx [I] Desired width
2215 * desiredy [I] Desired height
2216 * loadflags [I] Load flags
2218 * RETURNS
2219 * Success: Handle to newly loaded image
2220 * Failure: NULL
2222 * FIXME: Implementation lacks some features, see LR_ defines in winuser.h
2224 HANDLE WINAPI LoadImageW( HINSTANCE hinst, LPCWSTR name, UINT type,
2225 INT desiredx, INT desiredy, UINT loadflags )
2227 if (HIWORD(name)) {
2228 TRACE_(resource)("(0x%04x,%p,%d,%d,%d,0x%08x)\n",
2229 hinst,name,type,desiredx,desiredy,loadflags);
2230 } else {
2231 TRACE_(resource)("(0x%04x,%p,%d,%d,%d,0x%08x)\n",
2232 hinst,name,type,desiredx,desiredy,loadflags);
2234 if (loadflags & LR_DEFAULTSIZE) {
2235 if (type == IMAGE_ICON) {
2236 if (!desiredx) desiredx = GetSystemMetrics(SM_CXICON);
2237 if (!desiredy) desiredy = GetSystemMetrics(SM_CYICON);
2238 } else if (type == IMAGE_CURSOR) {
2239 if (!desiredx) desiredx = GetSystemMetrics(SM_CXCURSOR);
2240 if (!desiredy) desiredy = GetSystemMetrics(SM_CYCURSOR);
2243 if (loadflags & LR_LOADFROMFILE) loadflags &= ~LR_SHARED;
2244 switch (type) {
2245 case IMAGE_BITMAP:
2246 return BITMAP_Load( hinst, name, loadflags );
2248 case IMAGE_ICON:
2249 if (!screen_dc) screen_dc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
2250 if (screen_dc)
2252 UINT palEnts = GetSystemPaletteEntries(screen_dc, 0, 0, NULL);
2253 if (palEnts == 0) palEnts = 256;
2254 return CURSORICON_Load(hinst, name, desiredx, desiredy,
2255 palEnts, FALSE, loadflags);
2257 break;
2259 case IMAGE_CURSOR:
2260 return CURSORICON_Load(hinst, name, desiredx, desiredy,
2261 1, TRUE, loadflags);
2263 return 0;
2267 /******************************************************************************
2268 * CopyImage (USER.390) Creates new image and copies attributes to it
2271 HICON16 WINAPI CopyImage16( HANDLE16 hnd, UINT16 type, INT16 desiredx,
2272 INT16 desiredy, UINT16 flags )
2274 return (HICON16)CopyImage((HANDLE)hnd, (UINT)type, (INT)desiredx,
2275 (INT)desiredy, (UINT)flags);
2278 /******************************************************************************
2279 * CopyImage (USER32.@) Creates new image and copies attributes to it
2281 * PARAMS
2282 * hnd [I] Handle to image to copy
2283 * type [I] Type of image to copy
2284 * desiredx [I] Desired width of new image
2285 * desiredy [I] Desired height of new image
2286 * flags [I] Copy flags
2288 * RETURNS
2289 * Success: Handle to newly created image
2290 * Failure: NULL
2292 * FIXME: implementation still lacks nearly all features, see LR_*
2293 * defines in winuser.h
2295 HICON WINAPI CopyImage( HANDLE hnd, UINT type, INT desiredx,
2296 INT desiredy, UINT flags )
2298 switch (type)
2300 case IMAGE_BITMAP:
2301 return BITMAP_CopyBitmap(hnd);
2302 case IMAGE_ICON:
2303 return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags);
2304 case IMAGE_CURSOR:
2305 /* Should call CURSORICON_ExtCopy but more testing
2306 * needs to be done before we change this
2308 return CopyCursor(hnd);
2310 return 0;
2314 /******************************************************************************
2315 * LoadBitmapW (USER32.@) Loads bitmap from the executable file
2317 * RETURNS
2318 * Success: Handle to specified bitmap
2319 * Failure: NULL
2321 HBITMAP WINAPI LoadBitmapW(
2322 HINSTANCE instance, /* [in] Handle to application instance */
2323 LPCWSTR name) /* [in] Address of bitmap resource name */
2325 return LoadImageW( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2328 /**********************************************************************
2329 * LoadBitmapA (USER32.@)
2331 HBITMAP WINAPI LoadBitmapA( HINSTANCE instance, LPCSTR name )
2333 return LoadImageA( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2336 /**********************************************************************
2337 * LoadBitmap (USER.175)
2339 HBITMAP16 WINAPI LoadBitmap16( HINSTANCE16 instance, LPCSTR name )
2341 return LoadBitmapA( instance, name );