GetIconInfo did no correctly identify icons from cursors.
[wine.git] / windows / cursoricon.c
blobe7b2374eb3039d531222294da9046c6976ecadd7
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 "color.h"
41 #include "bitmap.h"
42 #include "cursoricon.h"
43 #include "dc.h"
44 #include "gdi.h"
45 #include "global.h"
46 #include "module.h"
47 #include "debugtools.h"
48 #include "task.h"
49 #include "user.h"
50 #include "input.h"
51 #include "message.h"
52 #include "winerror.h"
54 DECLARE_DEBUG_CHANNEL(cursor);
55 DECLARE_DEBUG_CHANNEL(icon);
56 DECLARE_DEBUG_CHANNEL(resource);
58 static HCURSOR hActiveCursor = 0; /* Active cursor */
59 static INT CURSOR_ShowCount = 0; /* Cursor display count */
60 static RECT CURSOR_ClipRect; /* Cursor clipping rect */
63 /**********************************************************************
64 * ICONCACHE for cursors/icons loaded with LR_SHARED.
66 * FIXME: This should not be allocated on the system heap, but on a
67 * subsystem-global heap (i.e. one for all Win16 processes,
68 * and one each for every Win32 process).
70 typedef struct tagICONCACHE
72 struct tagICONCACHE *next;
74 HMODULE hModule;
75 HRSRC hRsrc;
76 HRSRC hGroupRsrc;
77 HANDLE handle;
79 INT count;
81 } ICONCACHE;
83 static ICONCACHE *IconAnchor = NULL;
84 static CRITICAL_SECTION IconCrst = CRITICAL_SECTION_INIT;
85 static WORD ICON_HOTSPOT = 0x4242;
87 /**********************************************************************
88 * CURSORICON_FindSharedIcon
90 static HANDLE CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
92 HANDLE handle = 0;
93 ICONCACHE *ptr;
95 EnterCriticalSection( &IconCrst );
97 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
98 if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
100 ptr->count++;
101 handle = ptr->handle;
102 break;
105 LeaveCriticalSection( &IconCrst );
107 return handle;
110 /*************************************************************************
111 * CURSORICON_FindCache
113 * Given a handle, find the coresponding cache element
115 * PARAMS
116 * Handle [I] handle to an Image
118 * RETURNS
119 * Success: The cache entry
120 * Failure: NULL
123 static ICONCACHE* CURSORICON_FindCache(HANDLE handle)
125 ICONCACHE *ptr;
126 ICONCACHE *pRet=NULL;
127 BOOL IsFound = FALSE;
128 int count;
130 EnterCriticalSection( &IconCrst );
132 for (count = 0, ptr = IconAnchor; ptr != NULL && !IsFound; ptr = ptr->next, count++ )
134 if ( handle == ptr->handle )
136 IsFound = TRUE;
137 pRet = ptr;
141 LeaveCriticalSection( &IconCrst );
143 return pRet;
146 /**********************************************************************
147 * CURSORICON_AddSharedIcon
149 static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HRSRC hGroupRsrc, HANDLE handle )
151 ICONCACHE *ptr = HeapAlloc( SystemHeap, 0, sizeof(ICONCACHE) );
152 if ( !ptr ) return;
154 ptr->hModule = hModule;
155 ptr->hRsrc = hRsrc;
156 ptr->handle = handle;
157 ptr->hGroupRsrc = hGroupRsrc;
158 ptr->count = 1;
160 EnterCriticalSection( &IconCrst );
161 ptr->next = IconAnchor;
162 IconAnchor = ptr;
163 LeaveCriticalSection( &IconCrst );
166 /**********************************************************************
167 * CURSORICON_DelSharedIcon
169 static INT CURSORICON_DelSharedIcon( HANDLE handle )
171 INT count = -1;
172 ICONCACHE *ptr;
174 EnterCriticalSection( &IconCrst );
176 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
177 if ( ptr->handle == handle )
179 if ( ptr->count > 0 ) ptr->count--;
180 count = ptr->count;
181 break;
184 LeaveCriticalSection( &IconCrst );
186 return count;
189 /**********************************************************************
190 * CURSORICON_FreeModuleIcons
192 void CURSORICON_FreeModuleIcons( HMODULE hModule )
194 ICONCACHE **ptr = &IconAnchor;
196 if ( HIWORD( hModule ) )
197 hModule = MapHModuleLS( hModule );
198 else
199 hModule = GetExePtr( hModule );
201 EnterCriticalSection( &IconCrst );
203 while ( *ptr )
205 if ( (*ptr)->hModule == hModule )
207 ICONCACHE *freePtr = *ptr;
208 *ptr = freePtr->next;
210 GlobalFree16( freePtr->handle );
211 HeapFree( SystemHeap, 0, freePtr );
212 continue;
214 ptr = &(*ptr)->next;
217 LeaveCriticalSection( &IconCrst );
220 /**********************************************************************
221 * CURSORICON_FindBestIcon
223 * Find the icon closest to the requested size and number of colors.
225 static CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
226 int height, int colors )
228 int i;
229 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
230 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
231 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
233 if (dir->idCount < 1)
235 WARN_(icon)("Empty directory!\n" );
236 return NULL;
238 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
240 /* Find Best Fit */
241 iTotalDiff = 0xFFFFFFFF;
242 iColorDiff = 0xFFFFFFFF;
243 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
245 iTempXDiff = abs(width - entry->ResInfo.icon.bWidth);
246 iTempYDiff = abs(height - entry->ResInfo.icon.bHeight);
248 if(iTotalDiff > (iTempXDiff + iTempYDiff))
250 iXDiff = iTempXDiff;
251 iYDiff = iTempYDiff;
252 iTotalDiff = iXDiff + iYDiff;
256 /* Find Best Colors for Best Fit */
257 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
259 if(abs(width - entry->ResInfo.icon.bWidth) == iXDiff &&
260 abs(height - entry->ResInfo.icon.bHeight) == iYDiff)
262 iTempColorDiff = abs(colors - entry->ResInfo.icon.bColorCount);
263 if(iColorDiff > iTempColorDiff)
265 bestEntry = entry;
266 iColorDiff = iTempColorDiff;
271 return bestEntry;
275 /**********************************************************************
276 * CURSORICON_FindBestCursor
278 * Find the cursor closest to the requested size.
279 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
280 * ignored too
282 static CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
283 int width, int height, int color)
285 int i, maxwidth, maxheight;
286 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
288 if (dir->idCount < 1)
290 WARN_(cursor)("Empty directory!\n" );
291 return NULL;
293 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
295 /* Double height to account for AND and XOR masks */
297 height *= 2;
299 /* First find the largest one smaller than or equal to the requested size*/
301 maxwidth = maxheight = 0;
302 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
303 if ((entry->ResInfo.cursor.wWidth <= width) && (entry->ResInfo.cursor.wHeight <= height) &&
304 (entry->ResInfo.cursor.wWidth > maxwidth) && (entry->ResInfo.cursor.wHeight > maxheight) &&
305 (entry->wBitCount == 1))
307 bestEntry = entry;
308 maxwidth = entry->ResInfo.cursor.wWidth;
309 maxheight = entry->ResInfo.cursor.wHeight;
311 if (bestEntry) return bestEntry;
313 /* Now find the smallest one larger than the requested size */
315 maxwidth = maxheight = 255;
316 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
317 if ((entry->ResInfo.cursor.wWidth < maxwidth) && (entry->ResInfo.cursor.wHeight < maxheight) &&
318 (entry->wBitCount == 1))
320 bestEntry = entry;
321 maxwidth = entry->ResInfo.cursor.wWidth;
322 maxheight = entry->ResInfo.cursor.wHeight;
325 return bestEntry;
328 /*********************************************************************
329 * The main purpose of this function is to create fake resource directory
330 * and fake resource entries. There are several reasons for this:
331 * - CURSORICONDIR and CURSORICONFILEDIR differ in sizes and their
332 * fields
333 * There are some "bad" cursor files which do not have
334 * bColorCount initialized but instead one must read this info
335 * directly from corresponding DIB sections
336 * Note: wResId is index to array of pointer returned in ptrs (origin is 1)
338 BOOL CURSORICON_SimulateLoadingFromResourceW( LPWSTR filename, BOOL fCursor,
339 CURSORICONDIR **res, LPBYTE **ptr)
341 LPBYTE _free;
342 CURSORICONFILEDIR *bits;
343 int entries, size, i;
345 *res = NULL;
346 *ptr = NULL;
347 if (!(bits = (CURSORICONFILEDIR *)VIRTUAL_MapFileW( filename ))) return FALSE;
349 /* FIXME: test for inimated icons
350 * hack to load the first icon from the *.ani file
352 if ( *(LPDWORD)bits==0x46464952 ) /* "RIFF" */
353 { LPBYTE pos = (LPBYTE) bits;
354 FIXME_(cursor)("Animated icons not correctly implemented! %p \n", bits);
356 for (;;)
357 { if (*(LPDWORD)pos==0x6e6f6369) /* "icon" */
358 { FIXME_(cursor)("icon entry found! %p\n", bits);
359 pos+=4;
360 if ( !*(LPWORD) pos==0x2fe) /* iconsize */
361 { goto fail;
363 bits=(CURSORICONFILEDIR*)(pos+4);
364 FIXME_(cursor)("icon size ok. offset=%p \n", bits);
365 break;
367 pos+=2;
368 if (pos>=(LPBYTE)bits+766) goto fail;
371 if (!(entries = bits->idCount)) goto fail;
372 size = sizeof(CURSORICONDIR) + sizeof(CURSORICONDIRENTRY) * (entries - 1);
373 _free = (LPBYTE) size;
375 for (i=0; i < entries; i++)
376 size += bits->idEntries[i].dwDIBSize + (fCursor ? sizeof(POINT16): 0);
378 if (!(*ptr = HeapAlloc( GetProcessHeap(), 0,
379 entries * sizeof (CURSORICONDIRENTRY*)))) goto fail;
380 if (!(*res = HeapAlloc( GetProcessHeap(), 0, size))) goto fail;
382 _free = (LPBYTE)(*res) + (int)_free;
383 memcpy((*res), bits, 6);
384 for (i=0; i<entries; i++)
386 ((LPBYTE*)(*ptr))[i] = _free;
387 if (fCursor) {
388 (*res)->idEntries[i].ResInfo.cursor.wWidth=bits->idEntries[i].bWidth;
389 (*res)->idEntries[i].ResInfo.cursor.wHeight=bits->idEntries[i].bHeight;
390 ((LPPOINT16)_free)->x=bits->idEntries[i].xHotspot;
391 ((LPPOINT16)_free)->y=bits->idEntries[i].yHotspot;
392 _free+=sizeof(POINT16);
393 } else {
394 (*res)->idEntries[i].ResInfo.icon.bWidth=bits->idEntries[i].bWidth;
395 (*res)->idEntries[i].ResInfo.icon.bHeight=bits->idEntries[i].bHeight;
396 (*res)->idEntries[i].ResInfo.icon.bColorCount = bits->idEntries[i].bColorCount;
398 (*res)->idEntries[i].wPlanes=1;
399 (*res)->idEntries[i].wBitCount = ((LPBITMAPINFOHEADER)((LPBYTE)bits +
400 bits->idEntries[i].dwDIBOffset))->biBitCount;
401 (*res)->idEntries[i].dwBytesInRes = bits->idEntries[i].dwDIBSize;
402 (*res)->idEntries[i].wResId=i+1;
404 memcpy(_free,(LPBYTE)bits +bits->idEntries[i].dwDIBOffset,
405 (*res)->idEntries[i].dwBytesInRes);
406 _free += (*res)->idEntries[i].dwBytesInRes;
408 UnmapViewOfFile( bits );
409 return TRUE;
410 fail:
411 if (*res) HeapFree( GetProcessHeap(), 0, *res );
412 if (*ptr) HeapFree( GetProcessHeap(), 0, *ptr );
413 UnmapViewOfFile( bits );
414 return FALSE;
418 /**********************************************************************
419 * CURSORICON_CreateFromResource
421 * Create a cursor or icon from in-memory resource template.
423 * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
424 * with cbSize parameter as well.
426 static HGLOBAL16 CURSORICON_CreateFromResource( HINSTANCE16 hInstance, HGLOBAL16 hObj, LPBYTE bits,
427 UINT cbSize, BOOL bIcon, DWORD dwVersion,
428 INT width, INT height, UINT loadflags )
430 int sizeAnd, sizeXor;
431 HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
432 BITMAPOBJ *bmpXor, *bmpAnd;
433 POINT16 hotspot;
434 BITMAPINFO *bmi;
435 HDC hdc;
436 BOOL DoStretch;
437 INT size;
439 hotspot.x = ICON_HOTSPOT;
440 hotspot.y = ICON_HOTSPOT;
442 TRACE_(cursor)("%08x (%u bytes), ver %08x, %ix%i %s %s\n",
443 (unsigned)bits, cbSize, (unsigned)dwVersion, width, height,
444 bIcon ? "icon" : "cursor", (loadflags & LR_MONOCHROME) ? "mono" : "" );
445 if (dwVersion == 0x00020000)
447 FIXME_(cursor)("\t2.xx resources are not supported\n");
448 return 0;
451 if (bIcon)
452 bmi = (BITMAPINFO *)bits;
453 else /* get the hotspot */
455 POINT16 *pt = (POINT16 *)bits;
456 hotspot = *pt;
457 bmi = (BITMAPINFO *)(pt + 1);
459 size = DIB_BitmapInfoSize( bmi, DIB_RGB_COLORS );
461 if (!width) width = bmi->bmiHeader.biWidth;
462 if (!height) height = bmi->bmiHeader.biHeight/2;
463 DoStretch = (bmi->bmiHeader.biHeight/2 != height) ||
464 (bmi->bmiHeader.biWidth != width);
466 /* Check bitmap header */
468 if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
469 (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) ||
470 bmi->bmiHeader.biCompression != BI_RGB) )
472 WARN_(cursor)("\tinvalid resource bitmap header.\n");
473 return 0;
476 if( (hdc = GetDC( 0 )) )
478 BITMAPINFO* pInfo;
480 /* Make sure we have room for the monochrome bitmap later on.
481 * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
482 * up to and including the biBitCount. In-memory icon resource
483 * format is as follows:
485 * BITMAPINFOHEADER icHeader // DIB header
486 * RGBQUAD icColors[] // Color table
487 * BYTE icXOR[] // DIB bits for XOR mask
488 * BYTE icAND[] // DIB bits for AND mask
491 if ((pInfo = (BITMAPINFO *)HeapAlloc( GetProcessHeap(), 0,
492 max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))))
494 memcpy( pInfo, bmi, size );
495 pInfo->bmiHeader.biHeight /= 2;
497 /* Create the XOR bitmap */
499 if (DoStretch) {
500 if(bIcon)
502 hXorBits = CreateCompatibleBitmap(hdc, width, height);
504 else
506 hXorBits = CreateBitmap(width, height, 1, 1, NULL);
508 if(hXorBits)
510 HBITMAP hOld;
511 HDC hMem = CreateCompatibleDC(hdc);
512 BOOL res;
514 if (hMem) {
515 hOld = SelectObject(hMem, hXorBits);
516 res = StretchDIBits(hMem, 0, 0, width, height, 0, 0,
517 bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2,
518 (char*)bmi + size, pInfo, DIB_RGB_COLORS, SRCCOPY);
519 SelectObject(hMem, hOld);
520 DeleteDC(hMem);
521 } else res = FALSE;
522 if (!res) { DeleteObject(hXorBits); hXorBits = 0; }
524 } else hXorBits = CreateDIBitmap( hdc, &pInfo->bmiHeader,
525 CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS );
526 if( hXorBits )
528 char* bits = (char *)bmi + size +
529 DIB_GetDIBImageBytes(bmi->bmiHeader.biWidth,
530 bmi->bmiHeader.biHeight,
531 bmi->bmiHeader.biBitCount) / 2;
533 pInfo->bmiHeader.biBitCount = 1;
534 if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
536 RGBQUAD *rgb = pInfo->bmiColors;
538 pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
539 rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
540 rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
541 rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
543 else
545 RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
547 rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
548 rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
551 /* Create the AND bitmap */
553 if (DoStretch) {
554 if ((hAndBits = CreateBitmap(width, height, 1, 1, NULL))) {
555 HBITMAP hOld;
556 HDC hMem = CreateCompatibleDC(hdc);
557 BOOL res;
559 if (hMem) {
560 hOld = SelectObject(hMem, hAndBits);
561 res = StretchDIBits(hMem, 0, 0, width, height, 0, 0,
562 pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight,
563 bits, pInfo, DIB_RGB_COLORS, SRCCOPY);
564 SelectObject(hMem, hOld);
565 DeleteDC(hMem);
566 } else res = FALSE;
567 if (!res) { DeleteObject(hAndBits); hAndBits = 0; }
569 } else hAndBits = CreateDIBitmap( hdc, &pInfo->bmiHeader,
570 CBM_INIT, bits, pInfo, DIB_RGB_COLORS );
572 if( !hAndBits ) DeleteObject( hXorBits );
574 HeapFree( GetProcessHeap(), 0, pInfo );
576 ReleaseDC( 0, hdc );
579 if( !hXorBits || !hAndBits )
581 WARN_(cursor)("\tunable to create an icon bitmap.\n");
582 return 0;
585 /* Now create the CURSORICONINFO structure */
586 bmpXor = (BITMAPOBJ *) GDI_GetObjPtr( hXorBits, BITMAP_MAGIC );
587 bmpAnd = (BITMAPOBJ *) GDI_GetObjPtr( hAndBits, BITMAP_MAGIC );
588 sizeXor = bmpXor->bitmap.bmHeight * bmpXor->bitmap.bmWidthBytes;
589 sizeAnd = bmpAnd->bitmap.bmHeight * bmpAnd->bitmap.bmWidthBytes;
591 if (hObj) hObj = GlobalReAlloc16( hObj,
592 sizeof(CURSORICONINFO) + sizeXor + sizeAnd, GMEM_MOVEABLE );
593 if (!hObj) hObj = GlobalAlloc16( GMEM_MOVEABLE,
594 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
595 if (hObj)
597 CURSORICONINFO *info;
599 /* Make it owned by the module */
600 if (hInstance) FarSetOwner16( hObj, GetExePtr(hInstance) );
602 info = (CURSORICONINFO *)GlobalLock16( hObj );
603 info->ptHotSpot.x = hotspot.x;
604 info->ptHotSpot.y = hotspot.y;
605 info->nWidth = bmpXor->bitmap.bmWidth;
606 info->nHeight = bmpXor->bitmap.bmHeight;
607 info->nWidthBytes = bmpXor->bitmap.bmWidthBytes;
608 info->bPlanes = bmpXor->bitmap.bmPlanes;
609 info->bBitsPerPixel = bmpXor->bitmap.bmBitsPixel;
611 /* Transfer the bitmap bits to the CURSORICONINFO structure */
613 GetBitmapBits( hAndBits, sizeAnd, (char *)(info + 1) );
614 GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
615 GlobalUnlock16( hObj );
618 DeleteObject( hXorBits );
619 DeleteObject( hAndBits );
620 return hObj;
624 /**********************************************************************
625 * CreateIconFromResourceEx16 (USER.450)
627 * FIXME: not sure about exact parameter types
629 HICON16 WINAPI CreateIconFromResourceEx16( LPBYTE bits, UINT16 cbSize, BOOL16 bIcon,
630 DWORD dwVersion, INT16 width, INT16 height, UINT16 cFlag )
632 return CreateIconFromResourceEx(bits, cbSize, bIcon, dwVersion,
633 width, height, cFlag);
637 /**********************************************************************
638 * CreateIconFromResource (USER32.76)
640 HICON WINAPI CreateIconFromResource( LPBYTE bits, UINT cbSize,
641 BOOL bIcon, DWORD dwVersion)
643 return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
647 /**********************************************************************
648 * CreateIconFromResourceEx (USER32.77)
650 HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
651 BOOL bIcon, DWORD dwVersion,
652 INT width, INT height,
653 UINT cFlag )
655 TDB* pTask = (TDB*)GlobalLock16( GetCurrentTask() );
656 if( pTask )
657 return CURSORICON_CreateFromResource( pTask->hInstance, 0, bits, cbSize, bIcon, dwVersion,
658 width, height, cFlag );
659 return 0;
662 /**********************************************************************
663 * CURSORICON_Load
665 * Load a cursor or icon from resource or file.
667 HGLOBAL CURSORICON_Load( HINSTANCE hInstance, LPCWSTR name,
668 INT width, INT height, INT colors,
669 BOOL fCursor, UINT loadflags )
671 HANDLE handle = 0, h = 0;
672 HANDLE hRsrc;
673 CURSORICONDIR *dir;
674 CURSORICONDIRENTRY *dirEntry;
675 LPBYTE bits;
677 if ( loadflags & LR_LOADFROMFILE ) /* Load from file */
679 LPBYTE *ptr;
680 if (!CURSORICON_SimulateLoadingFromResourceW((LPWSTR)name, fCursor, &dir, &ptr))
681 return 0;
682 if (fCursor)
683 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(dir, width, height, 1);
684 else
685 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(dir, width, height, colors);
686 bits = ptr[dirEntry->wResId-1];
687 h = CURSORICON_CreateFromResource( 0, 0, bits, dirEntry->dwBytesInRes,
688 !fCursor, 0x00030000, width, height, loadflags);
689 HeapFree( GetProcessHeap(), 0, dir );
690 HeapFree( GetProcessHeap(), 0, ptr );
693 else if ( !hInstance ) /* Load OEM cursor/icon */
695 WORD resid;
696 HDC hdc;
698 if ( HIWORD(name) )
700 LPSTR ansi = HEAP_strdupWtoA(GetProcessHeap(),0,name);
701 if( ansi[0]=='#') /*Check for '#xxx' name */
703 resid = atoi(ansi+1);
704 HeapFree( GetProcessHeap(), 0, ansi );
706 else
708 HeapFree( GetProcessHeap(), 0, ansi );
709 return 0;
712 else resid = LOWORD(name);
713 hdc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
714 if (hdc) {
715 DC *dc = DC_GetDCPtr( hdc );
716 if (dc->funcs->pLoadOEMResource)
717 h = dc->funcs->pLoadOEMResource( resid, fCursor ? OEM_CURSOR : OEM_ICON );
718 GDI_HEAP_UNLOCK( hdc );
719 DeleteDC( hdc );
723 else /* Load from resource */
725 HANDLE hGroupRsrc;
726 WORD wResId;
727 DWORD dwBytesInRes;
729 /* Normalize hInstance (must be uniquely represented for icon cache) */
731 if ( HIWORD( hInstance ) )
732 hInstance = MapHModuleLS( hInstance );
733 else
734 hInstance = GetExePtr( hInstance );
736 /* Get directory resource ID */
738 if (!(hRsrc = FindResourceW( hInstance, name,
739 fCursor ? RT_GROUP_CURSORW : RT_GROUP_ICONW )))
740 return 0;
741 hGroupRsrc = hRsrc;
743 /* Find the best entry in the directory */
745 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
746 if (!(dir = (CURSORICONDIR*)LockResource( handle ))) return 0;
747 if (fCursor)
748 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor( dir,
749 width, height, 1);
750 else
751 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon( dir,
752 width, height, colors );
753 if (!dirEntry) return 0;
754 wResId = dirEntry->wResId;
755 dwBytesInRes = dirEntry->dwBytesInRes;
756 FreeResource( handle );
758 /* Load the resource */
760 if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
761 fCursor ? RT_CURSORW : RT_ICONW ))) return 0;
763 /* If shared icon, check whether it was already loaded */
764 if ( (loadflags & LR_SHARED)
765 && (h = CURSORICON_FindSharedIcon( hInstance, hRsrc ) ) != 0 )
766 return h;
768 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
769 bits = (LPBYTE)LockResource( handle );
770 h = CURSORICON_CreateFromResource( 0, 0, bits, dwBytesInRes,
771 !fCursor, 0x00030000, width, height, loadflags);
772 FreeResource( handle );
774 /* If shared icon, add to icon cache */
776 if ( h && (loadflags & LR_SHARED) )
777 CURSORICON_AddSharedIcon( hInstance, hRsrc, hGroupRsrc, h );
780 return h;
783 /***********************************************************************
784 * CURSORICON_Copy
786 * Make a copy of a cursor or icon.
788 static HGLOBAL16 CURSORICON_Copy( HINSTANCE16 hInstance, HGLOBAL16 handle )
790 char *ptrOld, *ptrNew;
791 int size;
792 HGLOBAL16 hNew;
794 if (!(ptrOld = (char *)GlobalLock16( handle ))) return 0;
795 if (!(hInstance = GetExePtr( hInstance ))) return 0;
796 size = GlobalSize16( handle );
797 hNew = GlobalAlloc16( GMEM_MOVEABLE, size );
798 FarSetOwner16( hNew, hInstance );
799 ptrNew = (char *)GlobalLock16( hNew );
800 memcpy( ptrNew, ptrOld, size );
801 GlobalUnlock16( handle );
802 GlobalUnlock16( hNew );
803 return hNew;
806 /*************************************************************************
807 * CURSORICON_ExtCopy
809 * Copies an Image from the Cache if LR_COPYFROMRESOURCE is specified
811 * PARAMS
812 * Handle [I] handle to an Image
813 * nType [I] Type of Handle (IMAGE_CURSOR | IMAGE_ICON)
814 * iDesiredCX [I] The Desired width of the Image
815 * iDesiredCY [I] The desired height of the Image
816 * nFlags [I] The flags from CopyImage
818 * RETURNS
819 * Success: The new handle of the Image
821 * NOTES
822 * LR_COPYDELETEORG and LR_MONOCHROME are currently not implemented.
823 * LR_MONOCHROME should be implemented by CURSORICON_CreateFromResource.
824 * LR_COPYFROMRESOURCE will only work if the Image is in the Cache.
829 HGLOBAL CURSORICON_ExtCopy(HGLOBAL Handle, UINT nType,
830 INT iDesiredCX, INT iDesiredCY,
831 UINT nFlags)
833 HGLOBAL16 hNew=0;
835 TRACE_(icon)("Handle %u, uType %u, iDesiredCX %i, iDesiredCY %i, nFlags %u\n",
836 Handle, nType, iDesiredCX, iDesiredCY, nFlags);
838 if(Handle == 0)
840 return 0;
843 /* Best Fit or Monochrome */
844 if( (nFlags & LR_COPYFROMRESOURCE
845 && (iDesiredCX > 0 || iDesiredCY > 0))
846 || nFlags & LR_MONOCHROME)
848 ICONCACHE* pIconCache = CURSORICON_FindCache(Handle);
850 /* Not Found in Cache, then do a strait copy
852 if(pIconCache == NULL)
854 TDB* pTask = (TDB *) GlobalLock16 (GetCurrentTask ());
855 hNew = CURSORICON_Copy(pTask->hInstance, Handle);
856 if(nFlags & LR_COPYFROMRESOURCE)
858 TRACE_(icon)("LR_COPYFROMRESOURCE: Failed to load from cache\n");
861 else
863 int iTargetCY = iDesiredCY, iTargetCX = iDesiredCX;
864 LPBYTE pBits;
865 HANDLE hMem;
866 HRSRC hRsrc;
867 DWORD dwBytesInRes;
868 WORD wResId;
869 CURSORICONDIR *pDir;
870 CURSORICONDIRENTRY *pDirEntry;
871 BOOL bIsIcon = (nType == IMAGE_ICON);
873 /* Completing iDesiredCX CY for Monochrome Bitmaps if needed
875 if(((nFlags & LR_MONOCHROME) && !(nFlags & LR_COPYFROMRESOURCE))
876 || (iDesiredCX == 0 && iDesiredCY == 0))
878 iDesiredCY = GetSystemMetrics(bIsIcon ?
879 SM_CYICON : SM_CYCURSOR);
880 iDesiredCX = GetSystemMetrics(bIsIcon ?
881 SM_CXICON : SM_CXCURSOR);
884 /* Retreive the CURSORICONDIRENTRY
886 if (!(hMem = LoadResource( pIconCache->hModule ,
887 pIconCache->hGroupRsrc)))
889 return 0;
891 if (!(pDir = (CURSORICONDIR*)LockResource( hMem )))
893 return 0;
896 /* Find Best Fit
898 if(bIsIcon)
900 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(
901 pDir, iDesiredCX, iDesiredCY, 256);
903 else
905 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(
906 pDir, iDesiredCX, iDesiredCY, 1);
909 wResId = pDirEntry->wResId;
910 dwBytesInRes = pDirEntry->dwBytesInRes;
911 FreeResource(hMem);
913 TRACE_(icon)("ResID %u, BytesInRes %lu, Width %d, Height %d DX %d, DY %d\n",
914 wResId, dwBytesInRes, pDirEntry->ResInfo.icon.bWidth,
915 pDirEntry->ResInfo.icon.bHeight, iDesiredCX, iDesiredCY);
917 /* Get the Best Fit
919 if (!(hRsrc = FindResourceW(pIconCache->hModule ,
920 MAKEINTRESOURCEW(wResId), bIsIcon ? RT_ICONW : RT_CURSORW)))
922 return 0;
924 if (!(hMem = LoadResource( pIconCache->hModule , hRsrc )))
926 return 0;
929 pBits = (LPBYTE)LockResource( hMem );
931 if(nFlags & LR_DEFAULTSIZE)
933 iTargetCY = GetSystemMetrics(SM_CYICON);
934 iTargetCX = GetSystemMetrics(SM_CXICON);
937 /* Create a New Icon with the proper dimension
939 hNew = CURSORICON_CreateFromResource( 0, 0, pBits, dwBytesInRes,
940 bIsIcon, 0x00030000, iTargetCX, iTargetCY, nFlags);
941 FreeResource(hMem);
944 else
946 TDB* pTask = (TDB *) GlobalLock16 (GetCurrentTask ());
947 hNew = CURSORICON_Copy(pTask->hInstance, Handle);
949 return hNew;
952 /***********************************************************************
953 * CURSORICON_IconToCursor
955 * Converts bitmap to mono and truncates if icon is too large (should
956 * probably do StretchBlt() instead).
958 HCURSOR16 CURSORICON_IconToCursor(HICON16 hIcon, BOOL bSemiTransparent)
960 HCURSOR16 hRet = 0;
961 CURSORICONINFO *pIcon = NULL;
962 HTASK16 hTask = GetCurrentTask();
963 TDB* pTask = (TDB *)GlobalLock16(hTask);
965 if(hIcon && pTask)
966 if (!(pIcon = (CURSORICONINFO*)GlobalLock16( hIcon ))) return FALSE;
967 if (pIcon->bPlanes * pIcon->bBitsPerPixel == 1)
969 hRet = CURSORICON_Copy( pTask->hInstance, hIcon );
972 pIcon = GlobalLock16(hRet);
974 pIcon->ptHotSpot.x = pIcon->ptHotSpot.y = 15;
976 GlobalUnlock16(hRet);
978 else
980 BYTE pAndBits[128];
981 BYTE pXorBits[128];
982 int maxx, maxy, ix, iy, bpp = pIcon->bBitsPerPixel;
983 BYTE* psPtr, *pxbPtr = pXorBits;
984 unsigned xor_width, and_width, val_base = 0xffffffff >> (32 - bpp);
985 BYTE* pbc = NULL;
987 CURSORICONINFO cI;
989 TRACE_(icon)("[%04x] %ix%i %ibpp (bogus %ibps)\n",
990 hIcon, pIcon->nWidth, pIcon->nHeight, pIcon->bBitsPerPixel, pIcon->nWidthBytes );
992 xor_width = BITMAP_GetWidthBytes( pIcon->nWidth, bpp );
993 and_width = BITMAP_GetWidthBytes( pIcon->nWidth, 1 );
994 psPtr = (BYTE *)(pIcon + 1) + pIcon->nHeight * and_width;
996 memset(pXorBits, 0, 128);
997 cI.bBitsPerPixel = 1; cI.bPlanes = 1;
998 cI.ptHotSpot.x = cI.ptHotSpot.y = 15;
999 cI.nWidth = 32; cI.nHeight = 32;
1000 cI.nWidthBytes = 4; /* 32x1bpp */
1002 maxx = (pIcon->nWidth > 32) ? 32 : pIcon->nWidth;
1003 maxy = (pIcon->nHeight > 32) ? 32 : pIcon->nHeight;
1005 for( iy = 0; iy < maxy; iy++ )
1007 unsigned shift = iy % 2;
1009 memcpy( pAndBits + iy * 4, (BYTE *)(pIcon + 1) + iy * and_width,
1010 (and_width > 4) ? 4 : and_width );
1011 for( ix = 0; ix < maxx; ix++ )
1013 if( bSemiTransparent && ((ix+shift)%2) )
1015 /* set AND bit, XOR bit stays 0 */
1017 pbc = pAndBits + iy * 4 + ix/8;
1018 *pbc |= 0x80 >> (ix%8);
1020 else
1022 /* keep AND bit, set XOR bit */
1024 unsigned *psc = (unsigned*)(psPtr + (ix * bpp)/8);
1025 unsigned val = ((*psc) >> (ix * bpp)%8) & val_base;
1026 if(!PALETTE_Driver->pIsDark(val))
1028 pbc = pxbPtr + ix/8;
1029 *pbc |= 0x80 >> (ix%8);
1033 psPtr += xor_width;
1034 pxbPtr += 4;
1037 hRet = CreateCursorIconIndirect16( pTask->hInstance , &cI, pAndBits, pXorBits);
1039 if( !hRet ) /* fall back on default drag cursor */
1040 hRet = CURSORICON_Copy( pTask->hInstance ,
1041 CURSORICON_Load(0,MAKEINTRESOURCEW(OCR_DRAGOBJECT),
1042 GetSystemMetrics(SM_CXCURSOR),
1043 GetSystemMetrics(SM_CYCURSOR), 1, TRUE, 0) );
1046 return hRet;
1050 /***********************************************************************
1051 * LoadCursor16 (USER.173)
1053 HCURSOR16 WINAPI LoadCursor16( HINSTANCE16 hInstance, SEGPTR name )
1055 LPCSTR nameStr = HIWORD(name)? PTR_SEG_TO_LIN(name) : (LPCSTR)name;
1056 return LoadCursorA( hInstance, nameStr );
1060 /***********************************************************************
1061 * LoadIcon16 (USER.174)
1063 HICON16 WINAPI LoadIcon16( HINSTANCE16 hInstance, SEGPTR name )
1065 LPCSTR nameStr = HIWORD(name)? PTR_SEG_TO_LIN(name) : (LPCSTR)name;
1066 return LoadIconA( hInstance, nameStr );
1070 /***********************************************************************
1071 * CreateCursor16 (USER.406)
1073 HCURSOR16 WINAPI CreateCursor16( HINSTANCE16 hInstance,
1074 INT16 xHotSpot, INT16 yHotSpot,
1075 INT16 nWidth, INT16 nHeight,
1076 LPCVOID lpANDbits, LPCVOID lpXORbits )
1078 CURSORICONINFO info;
1080 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1081 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1083 info.ptHotSpot.x = xHotSpot;
1084 info.ptHotSpot.y = yHotSpot;
1085 info.nWidth = nWidth;
1086 info.nHeight = nHeight;
1087 info.nWidthBytes = 0;
1088 info.bPlanes = 1;
1089 info.bBitsPerPixel = 1;
1091 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1095 /***********************************************************************
1096 * CreateCursor (USER32.67)
1098 HCURSOR WINAPI CreateCursor( HINSTANCE hInstance,
1099 INT xHotSpot, INT yHotSpot,
1100 INT nWidth, INT nHeight,
1101 LPCVOID lpANDbits, LPCVOID lpXORbits )
1103 CURSORICONINFO info;
1105 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1106 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1108 info.ptHotSpot.x = xHotSpot;
1109 info.ptHotSpot.y = yHotSpot;
1110 info.nWidth = nWidth;
1111 info.nHeight = nHeight;
1112 info.nWidthBytes = 0;
1113 info.bPlanes = 1;
1114 info.bBitsPerPixel = 1;
1116 return CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
1120 /***********************************************************************
1121 * CreateIcon16 (USER.407)
1123 HICON16 WINAPI CreateIcon16( HINSTANCE16 hInstance, INT16 nWidth,
1124 INT16 nHeight, BYTE bPlanes, BYTE bBitsPixel,
1125 LPCVOID lpANDbits, LPCVOID lpXORbits )
1127 CURSORICONINFO info;
1129 TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1130 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1132 info.ptHotSpot.x = ICON_HOTSPOT;
1133 info.ptHotSpot.y = ICON_HOTSPOT;
1134 info.nWidth = nWidth;
1135 info.nHeight = nHeight;
1136 info.nWidthBytes = 0;
1137 info.bPlanes = bPlanes;
1138 info.bBitsPerPixel = bBitsPixel;
1140 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1144 /***********************************************************************
1145 * CreateIcon (USER32.75)
1147 HICON WINAPI CreateIcon( HINSTANCE hInstance, INT nWidth,
1148 INT nHeight, BYTE bPlanes, BYTE bBitsPixel,
1149 LPCVOID lpANDbits, LPCVOID lpXORbits )
1151 CURSORICONINFO info;
1153 TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1154 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1156 info.ptHotSpot.x = ICON_HOTSPOT;
1157 info.ptHotSpot.y = ICON_HOTSPOT;
1158 info.nWidth = nWidth;
1159 info.nHeight = nHeight;
1160 info.nWidthBytes = 0;
1161 info.bPlanes = bPlanes;
1162 info.bBitsPerPixel = bBitsPixel;
1164 return CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
1168 /***********************************************************************
1169 * CreateCursorIconIndirect (USER.408)
1171 HGLOBAL16 WINAPI CreateCursorIconIndirect16( HINSTANCE16 hInstance,
1172 CURSORICONINFO *info,
1173 LPCVOID lpANDbits,
1174 LPCVOID lpXORbits )
1176 HGLOBAL16 handle;
1177 char *ptr;
1178 int sizeAnd, sizeXor;
1180 hInstance = GetExePtr( hInstance ); /* Make it a module handle */
1181 if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
1182 info->nWidthBytes = BITMAP_GetWidthBytes(info->nWidth,info->bBitsPerPixel);
1183 sizeXor = info->nHeight * info->nWidthBytes;
1184 sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
1185 if (!(handle = GlobalAlloc16( GMEM_MOVEABLE,
1186 sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
1187 return 0;
1188 if (hInstance) FarSetOwner16( handle, hInstance );
1189 ptr = (char *)GlobalLock16( handle );
1190 memcpy( ptr, info, sizeof(*info) );
1191 memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
1192 memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
1193 GlobalUnlock16( handle );
1194 return handle;
1198 /***********************************************************************
1199 * CopyIcon16 (USER.368)
1201 HICON16 WINAPI CopyIcon16( HINSTANCE16 hInstance, HICON16 hIcon )
1203 TRACE_(icon)("%04x %04x\n", hInstance, hIcon );
1204 return CURSORICON_Copy( hInstance, hIcon );
1208 /***********************************************************************
1209 * CopyIcon (USER32.60)
1211 HICON WINAPI CopyIcon( HICON hIcon )
1213 HTASK16 hTask = GetCurrentTask ();
1214 TDB* pTask = (TDB *) GlobalLock16 (hTask);
1215 TRACE_(icon)("%04x\n", hIcon );
1216 return CURSORICON_Copy( pTask->hInstance, hIcon );
1220 /***********************************************************************
1221 * CopyCursor16 (USER.369)
1223 HCURSOR16 WINAPI CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
1225 TRACE_(cursor)("%04x %04x\n", hInstance, hCursor );
1226 return CURSORICON_Copy( hInstance, hCursor );
1229 /**********************************************************************
1230 * CURSORICON_Destroy (USER.610)
1232 * This routine is actually exported from Win95 USER under the name
1233 * DestroyIcon32 ... The behaviour implemented here should mimic
1234 * the Win95 one exactly, especially the return values, which
1235 * depend on the setting of various flags.
1237 WORD WINAPI CURSORICON_Destroy( HGLOBAL16 handle, UINT16 flags )
1239 WORD retv;
1241 TRACE_(icon)("(%04x, %04x)\n", handle, flags );
1243 /* Check whether destroying active cursor */
1245 if ( hActiveCursor == handle )
1247 ERR_(cursor)("Destroying active cursor!\n" );
1248 SetCursor( 0 );
1251 /* Try shared cursor/icon first */
1253 if ( !(flags & CID_NONSHARED) )
1255 INT count = CURSORICON_DelSharedIcon( handle );
1257 if ( count != -1 )
1258 return (flags & CID_WIN32)? TRUE : (count == 0);
1260 /* FIXME: OEM cursors/icons should be recognized */
1263 /* Now assume non-shared cursor/icon */
1265 retv = GlobalFree16( handle );
1266 return (flags & CID_RESOURCE)? retv : TRUE;
1269 /***********************************************************************
1270 * DestroyIcon16 (USER.457)
1272 BOOL16 WINAPI DestroyIcon16( HICON16 hIcon )
1274 return CURSORICON_Destroy( hIcon, 0 );
1277 /***********************************************************************
1278 * DestroyIcon (USER32.133)
1280 BOOL WINAPI DestroyIcon( HICON hIcon )
1282 return CURSORICON_Destroy( hIcon, CID_WIN32 );
1285 /***********************************************************************
1286 * DestroyCursor16 (USER.458)
1288 BOOL16 WINAPI DestroyCursor16( HCURSOR16 hCursor )
1290 return CURSORICON_Destroy( hCursor, 0 );
1293 /***********************************************************************
1294 * DestroyCursor (USER32.132)
1296 BOOL WINAPI DestroyCursor( HCURSOR hCursor )
1298 return CURSORICON_Destroy( hCursor, CID_WIN32 );
1302 /***********************************************************************
1303 * DrawIcon16 (USER.84)
1305 BOOL16 WINAPI DrawIcon16( HDC16 hdc, INT16 x, INT16 y, HICON16 hIcon )
1307 return DrawIcon( hdc, x, y, hIcon );
1311 /***********************************************************************
1312 * DrawIcon (USER32.159)
1314 BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
1316 CURSORICONINFO *ptr;
1317 HDC hMemDC;
1318 HBITMAP hXorBits, hAndBits;
1319 COLORREF oldFg, oldBg;
1321 if (!(ptr = (CURSORICONINFO *)GlobalLock16( hIcon ))) return FALSE;
1322 if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
1323 hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1,
1324 (char *)(ptr+1) );
1325 hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
1326 ptr->bBitsPerPixel, (char *)(ptr + 1)
1327 + ptr->nHeight * BITMAP_GetWidthBytes(ptr->nWidth,1) );
1328 oldFg = SetTextColor( hdc, RGB(0,0,0) );
1329 oldBg = SetBkColor( hdc, RGB(255,255,255) );
1331 if (hXorBits && hAndBits)
1333 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1334 BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
1335 SelectObject( hMemDC, hXorBits );
1336 BitBlt(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
1337 SelectObject( hMemDC, hBitTemp );
1339 DeleteDC( hMemDC );
1340 if (hXorBits) DeleteObject( hXorBits );
1341 if (hAndBits) DeleteObject( hAndBits );
1342 GlobalUnlock16( hIcon );
1343 SetTextColor( hdc, oldFg );
1344 SetBkColor( hdc, oldBg );
1345 return TRUE;
1349 /***********************************************************************
1350 * IconSize16 (USER.86)
1352 * See "Undocumented Windows". Used by W2.0 paint.exe.
1354 DWORD WINAPI IconSize16( void )
1356 return MAKELONG(GetSystemMetrics(SM_CYICON), GetSystemMetrics(SM_CXICON));
1360 /***********************************************************************
1361 * DumpIcon (USER.459)
1363 DWORD WINAPI DumpIcon16( SEGPTR pInfo, WORD *lpLen,
1364 SEGPTR *lpXorBits, SEGPTR *lpAndBits )
1366 CURSORICONINFO *info = PTR_SEG_TO_LIN( pInfo );
1367 int sizeAnd, sizeXor;
1369 if (!info) return 0;
1370 sizeXor = info->nHeight * info->nWidthBytes;
1371 sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
1372 if (lpAndBits) *lpAndBits = pInfo + sizeof(CURSORICONINFO);
1373 if (lpXorBits) *lpXorBits = pInfo + sizeof(CURSORICONINFO) + sizeAnd;
1374 if (lpLen) *lpLen = sizeof(CURSORICONINFO) + sizeAnd + sizeXor;
1375 return MAKELONG( sizeXor, sizeXor );
1379 /***********************************************************************
1380 * SetCursor16 (USER.69)
1382 HCURSOR16 WINAPI SetCursor16( HCURSOR16 hCursor )
1384 return (HCURSOR16)SetCursor( hCursor );
1388 /***********************************************************************
1389 * SetCursor (USER32.472)
1390 * RETURNS:
1391 * A handle to the previous cursor shape.
1393 HCURSOR WINAPI SetCursor(
1394 HCURSOR hCursor /* Handle of cursor to show */
1396 HCURSOR hOldCursor;
1398 if (hCursor == hActiveCursor) return hActiveCursor; /* No change */
1399 TRACE_(cursor)("%04x\n", hCursor );
1400 hOldCursor = hActiveCursor;
1401 hActiveCursor = hCursor;
1402 /* Change the cursor shape only if it is visible */
1403 if (CURSOR_ShowCount >= 0)
1405 USER_Driver->pSetCursor( (CURSORICONINFO*)GlobalLock16( hActiveCursor ) );
1406 GlobalUnlock16( hActiveCursor );
1408 return hOldCursor;
1412 /***********************************************************************
1413 * SetCursorPos16 (USER.70)
1415 void WINAPI SetCursorPos16( INT16 x, INT16 y )
1417 SetCursorPos( x, y );
1421 /***********************************************************************
1422 * SetCursorPos (USER32.474)
1424 BOOL WINAPI SetCursorPos( INT x, INT y )
1426 USER_Driver->pMoveCursor( x, y );
1427 return TRUE;
1431 /***********************************************************************
1432 * ShowCursor16 (USER.71)
1434 INT16 WINAPI ShowCursor16( BOOL16 bShow )
1436 return ShowCursor( bShow );
1440 /***********************************************************************
1441 * ShowCursor (USER32.530)
1443 INT WINAPI ShowCursor( BOOL bShow )
1445 TRACE_(cursor)("%d, count=%d\n",
1446 bShow, CURSOR_ShowCount );
1448 if (bShow)
1450 if (++CURSOR_ShowCount == 0) /* Show it */
1452 USER_Driver->pSetCursor( (CURSORICONINFO*)GlobalLock16( hActiveCursor ) );
1453 GlobalUnlock16( hActiveCursor );
1456 else
1458 if (--CURSOR_ShowCount == -1) /* Hide it */
1459 USER_Driver->pSetCursor( NULL );
1461 return CURSOR_ShowCount;
1465 /***********************************************************************
1466 * GetCursor16 (USER.247)
1468 HCURSOR16 WINAPI GetCursor16(void)
1470 return hActiveCursor;
1474 /***********************************************************************
1475 * GetCursor (USER32.227)
1477 HCURSOR WINAPI GetCursor(void)
1479 return hActiveCursor;
1483 /***********************************************************************
1484 * ClipCursor16 (USER.16)
1486 BOOL16 WINAPI ClipCursor16( const RECT16 *rect )
1488 if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1489 else CONV_RECT16TO32( rect, &CURSOR_ClipRect );
1490 return TRUE;
1494 /***********************************************************************
1495 * ClipCursor (USER32.53)
1497 BOOL WINAPI ClipCursor( const RECT *rect )
1499 if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1500 else CopyRect( &CURSOR_ClipRect, rect );
1501 return TRUE;
1505 /***********************************************************************
1506 * GetCursorPos16 (USER.17)
1508 BOOL16 WINAPI GetCursorPos16( POINT16 *pt )
1510 if (!pt) return 0;
1512 pt->x = PosX;
1513 pt->y = PosY;
1515 TRACE_(cursor)("ret=%d,%d\n", pt->x, pt->y );
1516 return 1;
1520 /***********************************************************************
1521 * GetCursorPos (USER32.229)
1523 BOOL WINAPI GetCursorPos( POINT *pt )
1525 BOOL ret;
1527 POINT16 pt16;
1528 ret = GetCursorPos16( &pt16 );
1529 if (pt) CONV_POINT16TO32( &pt16, pt );
1530 return ((pt) ? ret : 0);
1534 /***********************************************************************
1535 * GetClipCursor16 (USER.309)
1537 void WINAPI GetClipCursor16( RECT16 *rect )
1539 if (rect) CONV_RECT32TO16( &CURSOR_ClipRect, rect );
1543 /***********************************************************************
1544 * GetClipCursor (USER32.221)
1546 BOOL WINAPI GetClipCursor( RECT *rect )
1548 if (rect)
1550 CopyRect( rect, &CURSOR_ClipRect );
1551 return TRUE;
1553 return FALSE;
1556 /**********************************************************************
1557 * LookupIconIdFromDirectoryEx16 (USER.364)
1559 * FIXME: exact parameter sizes
1561 INT16 WINAPI LookupIconIdFromDirectoryEx16( LPBYTE xdir, BOOL16 bIcon,
1562 INT16 width, INT16 height, UINT16 cFlag )
1564 CURSORICONDIR *dir = (CURSORICONDIR*)xdir;
1565 UINT16 retVal = 0;
1566 if( dir && !dir->idReserved && (dir->idType & 3) )
1568 CURSORICONDIRENTRY* entry;
1569 HDC hdc;
1570 UINT palEnts;
1571 int colors;
1572 hdc = GetDC(0);
1573 palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
1574 if (palEnts == 0)
1575 palEnts = 256;
1576 colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
1578 ReleaseDC(0, hdc);
1580 if( bIcon )
1581 entry = CURSORICON_FindBestIcon( dir, width, height, colors );
1582 else
1583 entry = CURSORICON_FindBestCursor( dir, width, height, 1);
1585 if( entry ) retVal = entry->wResId;
1587 else WARN_(cursor)("invalid resource directory\n");
1588 return retVal;
1591 /**********************************************************************
1592 * LookupIconIdFromDirectoryEx (USER32.380)
1594 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE dir, BOOL bIcon,
1595 INT width, INT height, UINT cFlag )
1597 return LookupIconIdFromDirectoryEx16( dir, bIcon, width, height, cFlag );
1600 /**********************************************************************
1601 * LookupIconIdFromDirectory (USER.???)
1603 INT16 WINAPI LookupIconIdFromDirectory16( LPBYTE dir, BOOL16 bIcon )
1605 return LookupIconIdFromDirectoryEx16( dir, bIcon,
1606 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1607 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1610 /**********************************************************************
1611 * LookupIconIdFromDirectory (USER32.379)
1613 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1615 return LookupIconIdFromDirectoryEx( dir, bIcon,
1616 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1617 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1620 /**********************************************************************
1621 * GetIconID (USER.455)
1623 WORD WINAPI GetIconID16( HGLOBAL16 hResource, DWORD resType )
1625 LPBYTE lpDir = (LPBYTE)GlobalLock16(hResource);
1627 TRACE_(cursor)("hRes=%04x, entries=%i\n",
1628 hResource, lpDir ? ((CURSORICONDIR*)lpDir)->idCount : 0);
1630 switch(resType)
1632 case RT_CURSOR16:
1633 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, FALSE,
1634 GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1635 case RT_ICON16:
1636 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, TRUE,
1637 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0 );
1638 default:
1639 WARN_(cursor)("invalid res type %ld\n", resType );
1641 return 0;
1644 /**********************************************************************
1645 * LoadCursorIconHandler (USER.336)
1647 * Supposed to load resources of Windows 2.x applications.
1649 HGLOBAL16 WINAPI LoadCursorIconHandler16( HGLOBAL16 hResource, HMODULE16 hModule, HRSRC16 hRsrc )
1651 FIXME_(cursor)("(%04x,%04x,%04x): old 2.x resources are not supported!\n",
1652 hResource, hModule, hRsrc);
1653 return (HGLOBAL16)0;
1656 /**********************************************************************
1657 * LoadDIBIconHandler (USER.357)
1659 * RT_ICON resource loader, installed by USER_SignalProc when module
1660 * is initialized.
1662 HGLOBAL16 WINAPI LoadDIBIconHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1664 /* If hResource is zero we must allocate a new memory block, if it's
1665 * non-zero but GlobalLock() returns NULL then it was discarded and
1666 * we have to recommit some memory, otherwise we just need to check
1667 * the block size. See LoadProc() in 16-bit SDK for more.
1670 hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1671 if( hMemObj )
1673 LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1674 hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1675 SizeofResource16(hModule, hRsrc), TRUE, 0x00030000,
1676 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR );
1678 return hMemObj;
1681 /**********************************************************************
1682 * LoadDIBCursorHandler (USER.356)
1684 * RT_CURSOR resource loader. Same as above.
1686 HGLOBAL16 WINAPI LoadDIBCursorHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1688 hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1689 if( hMemObj )
1691 LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1692 hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1693 SizeofResource16(hModule, hRsrc), FALSE, 0x00030000,
1694 GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1696 return hMemObj;
1699 /**********************************************************************
1700 * LoadIconHandler (USER.456)
1702 HICON16 WINAPI LoadIconHandler16( HGLOBAL16 hResource, BOOL16 bNew )
1704 LPBYTE bits = (LPBYTE)LockResource16( hResource );
1706 TRACE_(cursor)("hRes=%04x\n",hResource);
1708 return CURSORICON_CreateFromResource( 0, 0, bits, 0, TRUE,
1709 bNew ? 0x00030000 : 0x00020000, 0, 0, LR_DEFAULTCOLOR );
1712 /***********************************************************************
1713 * LoadCursorW (USER32.362)
1715 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
1717 return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0,
1718 LR_SHARED | LR_DEFAULTSIZE );
1721 /***********************************************************************
1722 * LoadCursorA (USER32.359)
1724 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
1726 return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0,
1727 LR_SHARED | LR_DEFAULTSIZE );
1730 /***********************************************************************
1731 * LoadCursorFromFileW (USER32.361)
1733 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
1735 return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0,
1736 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1739 /***********************************************************************
1740 * LoadCursorFromFileA (USER32.360)
1742 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
1744 return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0,
1745 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1748 /***********************************************************************
1749 * LoadIconW (USER32.364)
1751 HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
1753 return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0,
1754 LR_SHARED | LR_DEFAULTSIZE );
1757 /***********************************************************************
1758 * LoadIconA (USER32.363)
1760 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
1762 return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0,
1763 LR_SHARED | LR_DEFAULTSIZE );
1766 /**********************************************************************
1767 * GetIconInfo16 (USER.395)
1769 BOOL16 WINAPI GetIconInfo16(HICON16 hIcon,LPICONINFO16 iconinfo)
1771 ICONINFO ii32;
1772 BOOL16 ret = GetIconInfo((HICON)hIcon, &ii32);
1774 iconinfo->fIcon = ii32.fIcon;
1775 iconinfo->xHotspot = ii32.xHotspot;
1776 iconinfo->yHotspot = ii32.yHotspot;
1777 iconinfo->hbmMask = ii32.hbmMask;
1778 iconinfo->hbmColor = ii32.hbmColor;
1779 return ret;
1782 /**********************************************************************
1783 * GetIconInfo (USER32.242)
1785 BOOL WINAPI GetIconInfo(HICON hIcon,LPICONINFO iconinfo) {
1786 CURSORICONINFO *ciconinfo;
1788 ciconinfo = GlobalLock16(hIcon);
1789 if (!ciconinfo)
1790 return FALSE;
1792 if ( (ciconinfo->ptHotSpot.x == ICON_HOTSPOT) &&
1793 (ciconinfo->ptHotSpot.y == ICON_HOTSPOT) )
1795 iconinfo->fIcon = TRUE;
1796 iconinfo->xHotspot = ciconinfo->nWidth / 2;
1797 iconinfo->yHotspot = ciconinfo->nHeight / 2;
1799 else
1801 iconinfo->fIcon = FALSE;
1802 iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
1803 iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
1806 iconinfo->hbmColor = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1807 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
1808 (char *)(ciconinfo + 1)
1809 + ciconinfo->nHeight *
1810 BITMAP_GetWidthBytes (ciconinfo->nWidth,1) );
1811 iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1812 1, 1, (char *)(ciconinfo + 1));
1814 GlobalUnlock16(hIcon);
1816 return TRUE;
1819 /**********************************************************************
1820 * CreateIconIndirect (USER32.78)
1822 HICON WINAPI CreateIconIndirect(LPICONINFO iconinfo) {
1823 BITMAPOBJ *bmpXor,*bmpAnd;
1824 HICON hObj;
1825 int sizeXor,sizeAnd;
1827 bmpXor = (BITMAPOBJ *) GDI_GetObjPtr( iconinfo->hbmColor, BITMAP_MAGIC );
1828 bmpAnd = (BITMAPOBJ *) GDI_GetObjPtr( iconinfo->hbmMask, BITMAP_MAGIC );
1830 sizeXor = bmpXor->bitmap.bmHeight * bmpXor->bitmap.bmWidthBytes;
1831 sizeAnd = bmpAnd->bitmap.bmHeight * bmpAnd->bitmap.bmWidthBytes;
1833 hObj = GlobalAlloc16( GMEM_MOVEABLE,
1834 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
1835 if (hObj)
1837 CURSORICONINFO *info;
1839 info = (CURSORICONINFO *)GlobalLock16( hObj );
1841 /* If we are creating an icon, the hotspot is unused */
1842 if (iconinfo->fIcon)
1844 info->ptHotSpot.x = ICON_HOTSPOT;
1845 info->ptHotSpot.y = ICON_HOTSPOT;
1847 else
1849 info->ptHotSpot.x = iconinfo->xHotspot;
1850 info->ptHotSpot.y = iconinfo->yHotspot;
1853 info->nWidth = bmpXor->bitmap.bmWidth;
1854 info->nHeight = bmpXor->bitmap.bmHeight;
1855 info->nWidthBytes = bmpXor->bitmap.bmWidthBytes;
1856 info->bPlanes = bmpXor->bitmap.bmPlanes;
1857 info->bBitsPerPixel = bmpXor->bitmap.bmBitsPixel;
1859 /* Transfer the bitmap bits to the CURSORICONINFO structure */
1861 GetBitmapBits( iconinfo->hbmMask ,sizeAnd,(char*)(info + 1) );
1862 GetBitmapBits( iconinfo->hbmColor,sizeXor,(char*)(info + 1) +sizeAnd);
1863 GlobalUnlock16( hObj );
1865 return hObj;
1869 /**********************************************************************
1871 DrawIconEx16 (USER.394)
1873 BOOL16 WINAPI DrawIconEx16 (HDC16 hdc, INT16 xLeft, INT16 yTop, HICON16 hIcon,
1874 INT16 cxWidth, INT16 cyWidth, UINT16 istep,
1875 HBRUSH16 hbr, UINT16 flags)
1877 return DrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
1878 istep, hbr, flags);
1882 /******************************************************************************
1883 * DrawIconEx [USER32.160] Draws an icon or cursor on device context
1885 * NOTES
1886 * Why is this using SM_CXICON instead of SM_CXCURSOR?
1888 * PARAMS
1889 * hdc [I] Handle to device context
1890 * x0 [I] X coordinate of upper left corner
1891 * y0 [I] Y coordinate of upper left corner
1892 * hIcon [I] Handle to icon to draw
1893 * cxWidth [I] Width of icon
1894 * cyWidth [I] Height of icon
1895 * istep [I] Index of frame in animated cursor
1896 * hbr [I] Handle to background brush
1897 * flags [I] Icon-drawing flags
1899 * RETURNS
1900 * Success: TRUE
1901 * Failure: FALSE
1903 BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
1904 INT cxWidth, INT cyWidth, UINT istep,
1905 HBRUSH hbr, UINT flags )
1907 CURSORICONINFO *ptr = (CURSORICONINFO *)GlobalLock16 (hIcon);
1908 HDC hDC_off = 0, hMemDC = CreateCompatibleDC (hdc);
1909 BOOL result = FALSE, DoOffscreen = FALSE;
1910 HBITMAP hB_off = 0, hOld = 0;
1912 if (!ptr) return FALSE;
1914 if (istep)
1915 FIXME_(icon)("Ignoring istep=%d\n", istep);
1916 if (flags & DI_COMPAT)
1917 FIXME_(icon)("Ignoring flag DI_COMPAT\n");
1919 /* Calculate the size of the destination image. */
1920 if (cxWidth == 0)
1922 if (flags & DI_DEFAULTSIZE)
1923 cxWidth = GetSystemMetrics (SM_CXICON);
1924 else
1925 cxWidth = ptr->nWidth;
1927 if (cyWidth == 0)
1929 if (flags & DI_DEFAULTSIZE)
1930 cyWidth = GetSystemMetrics (SM_CYICON);
1931 else
1932 cyWidth = ptr->nHeight;
1935 if (!(DoOffscreen = (hbr >= STOCK_WHITE_BRUSH) && (hbr <=
1936 STOCK_HOLLOW_BRUSH)))
1938 GDIOBJHDR *object = (GDIOBJHDR *) GDI_HEAP_LOCK(hbr);
1939 if (object)
1941 UINT16 magic = object->wMagic;
1942 GDI_HEAP_UNLOCK(hbr);
1943 DoOffscreen = magic == BRUSH_MAGIC;
1946 if (DoOffscreen) {
1947 RECT r;
1949 r.left = 0;
1950 r.top = 0;
1951 r.right = cxWidth;
1952 r.bottom = cxWidth;
1954 hDC_off = CreateCompatibleDC(hdc);
1955 hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth);
1956 if (hDC_off && hB_off) {
1957 hOld = SelectObject(hDC_off, hB_off);
1958 FillRect(hDC_off, &r, hbr);
1962 if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
1964 HBITMAP hXorBits, hAndBits;
1965 COLORREF oldFg, oldBg;
1966 INT nStretchMode;
1968 nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
1970 hXorBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1971 ptr->bPlanes, ptr->bBitsPerPixel,
1972 (char *)(ptr + 1)
1973 + ptr->nHeight *
1974 BITMAP_GetWidthBytes(ptr->nWidth,1) );
1975 hAndBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1976 1, 1, (char *)(ptr+1) );
1977 oldFg = SetTextColor( hdc, RGB(0,0,0) );
1978 oldBg = SetBkColor( hdc, RGB(255,255,255) );
1980 if (hXorBits && hAndBits)
1982 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1983 if (flags & DI_MASK)
1985 if (DoOffscreen)
1986 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1987 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1988 else
1989 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
1990 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1992 SelectObject( hMemDC, hXorBits );
1993 if (flags & DI_IMAGE)
1995 if (DoOffscreen)
1996 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1997 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
1998 else
1999 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
2000 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
2002 SelectObject( hMemDC, hBitTemp );
2003 result = TRUE;
2006 SetTextColor( hdc, oldFg );
2007 SetBkColor( hdc, oldBg );
2008 if (hXorBits) DeleteObject( hXorBits );
2009 if (hAndBits) DeleteObject( hAndBits );
2010 SetStretchBltMode (hdc, nStretchMode);
2011 if (DoOffscreen) {
2012 BitBlt(hdc, x0, y0, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
2013 SelectObject(hDC_off, hOld);
2016 if (hMemDC) DeleteDC( hMemDC );
2017 if (hDC_off) DeleteDC(hDC_off);
2018 if (hB_off) DeleteObject(hB_off);
2019 GlobalUnlock16( hIcon );
2020 return result;
2023 /***********************************************************************
2024 * DIB_FixColorsToLoadflags
2026 * Change color table entries when LR_LOADTRANSPARENT or LR_LOADMAP3DCOLORS
2027 * are in loadflags
2029 static void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags, BYTE pix)
2031 int colors;
2032 COLORREF c_W, c_S, c_F, c_L, c_C;
2033 int incr,i;
2034 RGBQUAD *ptr;
2036 if (bmi->bmiHeader.biBitCount > 8) return;
2037 if (bmi->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)) incr = 4;
2038 else if (bmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) incr = 3;
2039 else {
2040 WARN_(resource)("Wrong bitmap header size!\n");
2041 return;
2043 colors = bmi->bmiHeader.biClrUsed;
2044 if (!colors && (bmi->bmiHeader.biBitCount <= 8))
2045 colors = 1 << bmi->bmiHeader.biBitCount;
2046 c_W = GetSysColor(COLOR_WINDOW);
2047 c_S = GetSysColor(COLOR_3DSHADOW);
2048 c_F = GetSysColor(COLOR_3DFACE);
2049 c_L = GetSysColor(COLOR_3DLIGHT);
2050 if (loadflags & LR_LOADTRANSPARENT) {
2051 switch (bmi->bmiHeader.biBitCount) {
2052 case 1: pix = pix >> 7; break;
2053 case 4: pix = pix >> 4; break;
2054 case 8: break;
2055 default:
2056 WARN_(resource)("(%d): Unsupported depth\n", bmi->bmiHeader.biBitCount);
2057 return;
2059 if (pix >= colors) {
2060 WARN_(resource)("pixel has color index greater than biClrUsed!\n");
2061 return;
2063 if (loadflags & LR_LOADMAP3DCOLORS) c_W = c_F;
2064 ptr = (RGBQUAD*)((char*)bmi->bmiColors+pix*incr);
2065 ptr->rgbBlue = GetBValue(c_W);
2066 ptr->rgbGreen = GetGValue(c_W);
2067 ptr->rgbRed = GetRValue(c_W);
2069 if (loadflags & LR_LOADMAP3DCOLORS)
2070 for (i=0; i<colors; i++) {
2071 ptr = (RGBQUAD*)((char*)bmi->bmiColors+i*incr);
2072 c_C = RGB(ptr->rgbRed, ptr->rgbGreen, ptr->rgbBlue);
2073 if (c_C == RGB(128, 128, 128)) {
2074 ptr->rgbRed = GetRValue(c_S);
2075 ptr->rgbGreen = GetGValue(c_S);
2076 ptr->rgbBlue = GetBValue(c_S);
2077 } else if (c_C == RGB(192, 192, 192)) {
2078 ptr->rgbRed = GetRValue(c_F);
2079 ptr->rgbGreen = GetGValue(c_F);
2080 ptr->rgbBlue = GetBValue(c_F);
2081 } else if (c_C == RGB(223, 223, 223)) {
2082 ptr->rgbRed = GetRValue(c_L);
2083 ptr->rgbGreen = GetGValue(c_L);
2084 ptr->rgbBlue = GetBValue(c_L);
2090 /**********************************************************************
2091 * BITMAP_Load
2093 static HBITMAP BITMAP_Load( HINSTANCE instance,LPCWSTR name, UINT loadflags )
2095 HBITMAP hbitmap = 0;
2096 HDC hdc;
2097 HRSRC hRsrc;
2098 HGLOBAL handle;
2099 char *ptr = NULL;
2100 BITMAPINFO *info, *fix_info=NULL;
2101 HGLOBAL hFix;
2102 int size;
2104 if (!(loadflags & LR_LOADFROMFILE)) {
2105 if (!instance) /* OEM bitmap */
2107 HDC hdc;
2108 DC *dc;
2110 if (HIWORD((int)name)) return 0;
2111 hdc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
2112 dc = DC_GetDCPtr( hdc );
2113 if(dc->funcs->pLoadOEMResource)
2114 hbitmap = dc->funcs->pLoadOEMResource( LOWORD((int)name),
2115 OEM_BITMAP );
2116 GDI_HEAP_UNLOCK( hdc );
2117 DeleteDC( hdc );
2118 return hbitmap;
2121 if (!(hRsrc = FindResourceW( instance, name, RT_BITMAPW ))) return 0;
2122 if (!(handle = LoadResource( instance, hRsrc ))) return 0;
2124 if ((info = (BITMAPINFO *)LockResource( handle )) == NULL) return 0;
2126 else
2128 if (!(ptr = (char *)VIRTUAL_MapFileW( name ))) return 0;
2129 info = (BITMAPINFO *)(ptr + sizeof(BITMAPFILEHEADER));
2131 size = DIB_BitmapInfoSize(info, DIB_RGB_COLORS);
2132 if ((hFix = GlobalAlloc(0, size))) fix_info=GlobalLock(hFix);
2133 if (fix_info) {
2134 BYTE pix;
2136 memcpy(fix_info, info, size);
2137 pix = *((LPBYTE)info+DIB_BitmapInfoSize(info, DIB_RGB_COLORS));
2138 DIB_FixColorsToLoadflags(fix_info, loadflags, pix);
2139 if ((hdc = GetDC(0)) != 0) {
2140 char *bits = (char *)info + size;
2141 if (loadflags & LR_CREATEDIBSECTION) {
2142 DIBSECTION dib;
2143 hbitmap = CreateDIBSection(hdc, fix_info, DIB_RGB_COLORS, NULL, 0, 0);
2144 GetObjectA(hbitmap, sizeof(DIBSECTION), &dib);
2145 SetDIBits(hdc, hbitmap, 0, dib.dsBm.bmHeight, bits, info,
2146 DIB_RGB_COLORS);
2148 else {
2149 hbitmap = CreateDIBitmap( hdc, &fix_info->bmiHeader, CBM_INIT,
2150 bits, fix_info, DIB_RGB_COLORS );
2152 ReleaseDC( 0, hdc );
2154 GlobalUnlock(hFix);
2155 GlobalFree(hFix);
2157 if (loadflags & LR_LOADFROMFILE) UnmapViewOfFile( ptr );
2158 return hbitmap;
2162 /***********************************************************************
2163 * LoadImage16 [USER.389]
2166 HANDLE16 WINAPI LoadImage16( HINSTANCE16 hinst, LPCSTR name, UINT16 type,
2167 INT16 desiredx, INT16 desiredy, UINT16 loadflags)
2169 LPCSTR nameStr = HIWORD(name)? PTR_SEG_TO_LIN(name) : (LPCSTR)name;
2170 return LoadImageA( hinst, nameStr, type,
2171 desiredx, desiredy, loadflags );
2174 /**********************************************************************
2175 * LoadImageA (USER32.365)
2177 * FIXME: implementation lacks some features, see LR_ defines in windows.h
2180 HANDLE WINAPI LoadImageA( HINSTANCE hinst, LPCSTR name, UINT type,
2181 INT desiredx, INT desiredy, UINT loadflags)
2183 HANDLE res;
2184 LPWSTR u_name;
2186 if (HIWORD(name)) u_name = HEAP_strdupAtoW(GetProcessHeap(), 0, name);
2187 else u_name=(LPWSTR)name;
2188 res = LoadImageW(hinst, u_name, type, desiredx, desiredy, loadflags);
2189 if (HIWORD(name)) HeapFree(GetProcessHeap(), 0, u_name);
2190 return res;
2194 /******************************************************************************
2195 * LoadImageW [USER32.366] Loads an icon, cursor, or bitmap
2197 * PARAMS
2198 * hinst [I] Handle of instance that contains image
2199 * name [I] Name of image
2200 * type [I] Type of image
2201 * desiredx [I] Desired width
2202 * desiredy [I] Desired height
2203 * loadflags [I] Load flags
2205 * RETURNS
2206 * Success: Handle to newly loaded image
2207 * Failure: NULL
2209 * FIXME: Implementation lacks some features, see LR_ defines in windows.h
2211 HANDLE WINAPI LoadImageW( HINSTANCE hinst, LPCWSTR name, UINT type,
2212 INT desiredx, INT desiredy, UINT loadflags )
2214 if (HIWORD(name)) {
2215 TRACE_(resource)("(0x%04x,%p,%d,%d,%d,0x%08x)\n",
2216 hinst,name,type,desiredx,desiredy,loadflags);
2217 } else {
2218 TRACE_(resource)("(0x%04x,%p,%d,%d,%d,0x%08x)\n",
2219 hinst,name,type,desiredx,desiredy,loadflags);
2221 if (loadflags & LR_DEFAULTSIZE) {
2222 if (type == IMAGE_ICON) {
2223 if (!desiredx) desiredx = GetSystemMetrics(SM_CXICON);
2224 if (!desiredy) desiredy = GetSystemMetrics(SM_CYICON);
2225 } else if (type == IMAGE_CURSOR) {
2226 if (!desiredx) desiredx = GetSystemMetrics(SM_CXCURSOR);
2227 if (!desiredy) desiredy = GetSystemMetrics(SM_CYCURSOR);
2230 if (loadflags & LR_LOADFROMFILE) loadflags &= ~LR_SHARED;
2231 switch (type) {
2232 case IMAGE_BITMAP:
2233 return BITMAP_Load( hinst, name, loadflags );
2235 case IMAGE_ICON:
2237 HDC hdc = GetDC(0);
2238 UINT palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
2239 if (palEnts == 0)
2240 palEnts = 256;
2241 ReleaseDC(0, hdc);
2243 return CURSORICON_Load(hinst, name, desiredx, desiredy,
2244 palEnts, FALSE, loadflags);
2247 case IMAGE_CURSOR:
2248 return CURSORICON_Load(hinst, name, desiredx, desiredy,
2249 1, TRUE, loadflags);
2251 return 0;
2255 /******************************************************************************
2256 * CopyImage16 [USER.390] Creates new image and copies attributes to it
2259 HICON16 WINAPI CopyImage16( HANDLE16 hnd, UINT16 type, INT16 desiredx,
2260 INT16 desiredy, UINT16 flags )
2262 return (HICON16)CopyImage((HANDLE)hnd, (UINT)type, (INT)desiredx,
2263 (INT)desiredy, (UINT)flags);
2266 /******************************************************************************
2267 * CopyImage [USER32.61] Creates new image and copies attributes to it
2269 * PARAMS
2270 * hnd [I] Handle to image to copy
2271 * type [I] Type of image to copy
2272 * desiredx [I] Desired width of new image
2273 * desiredy [I] Desired height of new image
2274 * flags [I] Copy flags
2276 * RETURNS
2277 * Success: Handle to newly created image
2278 * Failure: NULL
2280 * FIXME: implementation still lacks nearly all features, see LR_*
2281 * defines in windows.h
2283 HICON WINAPI CopyImage( HANDLE hnd, UINT type, INT desiredx,
2284 INT desiredy, UINT flags )
2286 switch (type)
2288 case IMAGE_BITMAP:
2289 return BITMAP_CopyBitmap(hnd);
2290 case IMAGE_ICON:
2291 return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags);
2292 case IMAGE_CURSOR:
2293 /* Should call CURSORICON_ExtCopy but more testing
2294 * needs to be done before we change this
2296 return CopyCursor(hnd);
2298 return 0;
2302 /******************************************************************************
2303 * LoadBitmapW [USER32.358] Loads bitmap from the executable file
2305 * RETURNS
2306 * Success: Handle to specified bitmap
2307 * Failure: NULL
2309 HBITMAP WINAPI LoadBitmapW(
2310 HINSTANCE instance, /* [in] Handle to application instance */
2311 LPCWSTR name) /* [in] Address of bitmap resource name */
2313 return LoadImageW( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2316 /**********************************************************************
2317 * LoadBitmapA (USER32.357)
2319 HBITMAP WINAPI LoadBitmapA( HINSTANCE instance, LPCSTR name )
2321 return LoadImageA( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2324 /**********************************************************************
2325 * LoadBitmap16 (USER.175)
2327 HBITMAP16 WINAPI LoadBitmap16( HINSTANCE16 instance, SEGPTR name )
2329 LPCSTR nameStr = HIWORD(name)? PTR_SEG_TO_LIN(name) : (LPCSTR)name;
2330 return LoadBitmapA( instance, nameStr );