Pierre Mageau
[wine/multimedia.git] / objects / cursoricon.c
bloba2051b3ca68244a677cd39926b5d9bfd5c4600a0
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 "wine/winbase16.h"
36 #include "wine/winuser16.h"
37 #include "heap.h"
38 #include "color.h"
39 #include "bitmap.h"
40 #include "cursoricon.h"
41 #include "dc.h"
42 #include "gdi.h"
43 #include "global.h"
44 #include "module.h"
45 #include "debugtools.h"
46 #include "task.h"
47 #include "user.h"
48 #include "input.h"
49 #include "display.h"
50 #include "message.h"
51 #include "winerror.h"
53 DECLARE_DEBUG_CHANNEL(cursor)
54 DECLARE_DEBUG_CHANNEL(icon)
56 static HCURSOR hActiveCursor = 0; /* Active cursor */
57 static INT CURSOR_ShowCount = 0; /* Cursor display count */
58 static RECT CURSOR_ClipRect; /* Cursor clipping rect */
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 each for every 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;
83 static DWORD ICON_HOTSPOT = 0x42424242;
85 /**********************************************************************
86 * CURSORICON_Init
88 void CURSORICON_Init( void )
90 InitializeCriticalSection( &IconCrst );
91 MakeCriticalSectionGlobal( &IconCrst );
94 /**********************************************************************
95 * CURSORICON_FindSharedIcon
97 static HANDLE CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
99 HANDLE handle = 0;
100 ICONCACHE *ptr;
102 EnterCriticalSection( &IconCrst );
104 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
105 if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
107 ptr->count++;
108 handle = ptr->handle;
109 break;
112 LeaveCriticalSection( &IconCrst );
114 return handle;
117 /*************************************************************************
118 * CURSORICON_FindCache
120 * Given a handle, find the coresponding cache element
122 * PARAMS
123 * Handle [I] handle to an Image
125 * RETURNS
126 * Success: The cache entry
127 * Failure: NULL
130 static ICONCACHE* CURSORICON_FindCache(HANDLE handle)
132 ICONCACHE *ptr;
133 ICONCACHE *pRet=NULL;
134 BOOL IsFound = FALSE;
135 int count;
137 EnterCriticalSection( &IconCrst );
139 for (count = 0, ptr = IconAnchor; ptr != NULL && !IsFound; ptr = ptr->next, count++ )
141 if ( handle == ptr->handle )
143 IsFound = TRUE;
144 pRet = ptr;
148 LeaveCriticalSection( &IconCrst );
150 return pRet;
153 /**********************************************************************
154 * CURSORICON_AddSharedIcon
156 static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HRSRC hGroupRsrc, HANDLE handle )
158 ICONCACHE *ptr = HeapAlloc( SystemHeap, 0, sizeof(ICONCACHE) );
159 if ( !ptr ) return;
161 ptr->hModule = hModule;
162 ptr->hRsrc = hRsrc;
163 ptr->handle = handle;
164 ptr->hGroupRsrc = hGroupRsrc;
165 ptr->count = 1;
167 EnterCriticalSection( &IconCrst );
168 ptr->next = IconAnchor;
169 IconAnchor = ptr;
170 LeaveCriticalSection( &IconCrst );
173 /**********************************************************************
174 * CURSORICON_DelSharedIcon
176 static INT CURSORICON_DelSharedIcon( HANDLE handle )
178 INT count = -1;
179 ICONCACHE *ptr;
181 EnterCriticalSection( &IconCrst );
183 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
184 if ( ptr->handle == handle )
186 if ( ptr->count > 0 ) ptr->count--;
187 count = ptr->count;
188 break;
191 LeaveCriticalSection( &IconCrst );
193 return count;
196 /**********************************************************************
197 * CURSORICON_FreeModuleIcons
199 void CURSORICON_FreeModuleIcons( HMODULE hModule )
201 ICONCACHE **ptr = &IconAnchor;
203 if ( HIWORD( hModule ) )
204 hModule = MapHModuleLS( hModule );
205 else
206 hModule = GetExePtr( hModule );
208 EnterCriticalSection( &IconCrst );
210 while ( *ptr )
212 if ( (*ptr)->hModule == hModule )
214 ICONCACHE *freePtr = *ptr;
215 *ptr = freePtr->next;
217 GlobalFree16( freePtr->handle );
218 HeapFree( SystemHeap, 0, freePtr );
219 continue;
221 ptr = &(*ptr)->next;
224 LeaveCriticalSection( &IconCrst );
227 /**********************************************************************
228 * CURSORICON_FindBestIcon
230 * Find the icon closest to the requested size and number of colors.
232 static CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
233 int height, int colors )
235 int i;
236 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
237 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
238 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
240 if (dir->idCount < 1)
242 WARN_(icon)("Empty directory!\n" );
243 return NULL;
245 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
247 /* Find Best Fit */
248 iTotalDiff = 0xFFFFFFFF;
249 iColorDiff = 0xFFFFFFFF;
250 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
252 iTempXDiff = abs(width - entry->ResInfo.icon.bWidth);
253 iTempYDiff = abs(height - entry->ResInfo.icon.bHeight);
255 if(iTotalDiff > (iTempXDiff + iTempYDiff))
257 iXDiff = iTempXDiff;
258 iYDiff = iTempYDiff;
259 iTotalDiff = iXDiff + iYDiff;
263 /* Find Best Colors for Best Fit */
264 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
266 if(abs(width - entry->ResInfo.icon.bWidth) == iXDiff &&
267 abs(height - entry->ResInfo.icon.bHeight) == iYDiff)
269 iTempColorDiff = abs(colors - entry->ResInfo.icon.bColorCount);
270 if(iColorDiff > iTempColorDiff)
272 bestEntry = entry;
273 iColorDiff = iTempColorDiff;
278 return bestEntry;
282 /**********************************************************************
283 * CURSORICON_FindBestCursor
285 * Find the cursor closest to the requested size.
286 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
287 * ignored too
289 static CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
290 int width, int height, int color)
292 int i, maxwidth, maxheight;
293 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
295 if (dir->idCount < 1)
297 WARN_(cursor)("Empty directory!\n" );
298 return NULL;
300 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
302 /* Double height to account for AND and XOR masks */
304 height *= 2;
306 /* First find the largest one smaller than or equal to the requested size*/
308 maxwidth = maxheight = 0;
309 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
310 if ((entry->ResInfo.cursor.wWidth <= width) && (entry->ResInfo.cursor.wHeight <= height) &&
311 (entry->ResInfo.cursor.wWidth > maxwidth) && (entry->ResInfo.cursor.wHeight > maxheight) &&
312 (entry->wBitCount == 1))
314 bestEntry = entry;
315 maxwidth = entry->ResInfo.cursor.wWidth;
316 maxheight = entry->ResInfo.cursor.wHeight;
318 if (bestEntry) return bestEntry;
320 /* Now find the smallest one larger than the requested size */
322 maxwidth = maxheight = 255;
323 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
324 if ((entry->ResInfo.cursor.wWidth < maxwidth) && (entry->ResInfo.cursor.wHeight < maxheight) &&
325 (entry->wBitCount == 1))
327 bestEntry = entry;
328 maxwidth = entry->ResInfo.cursor.wWidth;
329 maxheight = entry->ResInfo.cursor.wHeight;
332 return bestEntry;
335 /*********************************************************************
336 * The main purpose of this function is to create fake resource directory
337 * and fake resource entries. There are several reasons for this:
338 * - CURSORICONDIR and CURSORICONFILEDIR differ in sizes and their
339 * fields
340 * There are some "bad" cursor files which do not have
341 * bColorCount initialized but instead one must read this info
342 * directly from corresponding DIB sections
343 * Note: wResId is index to array of pointer returned in ptrs (origin is 1)
345 BOOL CURSORICON_SimulateLoadingFromResourceW( LPWSTR filename, BOOL fCursor,
346 CURSORICONDIR **res, LPBYTE **ptr)
348 LPBYTE _free;
349 CURSORICONFILEDIR *bits;
350 int entries, size, i;
352 *res = NULL;
353 *ptr = NULL;
354 if (!(bits = (CURSORICONFILEDIR *)VIRTUAL_MapFileW( filename ))) return FALSE;
356 /* FIXME: test for inimated icons
357 * hack to load the first icon from the *.ani file
359 if ( *(LPDWORD)bits==0x46464952 ) /* "RIFF" */
360 { LPBYTE pos = (LPBYTE) bits;
361 FIXME_(cursor)("Animated icons not correctly implemented! %p \n", bits);
363 for (;;)
364 { if (*(LPDWORD)pos==0x6e6f6369) /* "icon" */
365 { FIXME_(cursor)("icon entry found! %p\n", bits);
366 pos+=4;
367 if ( !*(LPWORD) pos==0x2fe) /* iconsize */
368 { goto fail;
370 bits=(CURSORICONFILEDIR*)(pos+4);
371 FIXME_(cursor)("icon size ok. offset=%p \n", bits);
372 break;
374 pos+=2;
375 if (pos>=(LPBYTE)bits+766) goto fail;
378 if (!(entries = bits->idCount)) goto fail;
379 size = sizeof(CURSORICONDIR) + sizeof(CURSORICONDIRENTRY) * (entries - 1);
380 _free = (LPBYTE) size;
382 for (i=0; i < entries; i++)
383 size += bits->idEntries[i].dwDIBSize + (fCursor ? sizeof(POINT16): 0);
385 if (!(*ptr = HeapAlloc( GetProcessHeap(), 0,
386 entries * sizeof (CURSORICONDIRENTRY*)))) goto fail;
387 if (!(*res = HeapAlloc( GetProcessHeap(), 0, size))) goto fail;
389 _free = (LPBYTE)(*res) + (int)_free;
390 memcpy((*res), bits, 6);
391 for (i=0; i<entries; i++)
393 ((LPBYTE*)(*ptr))[i] = _free;
394 if (fCursor) {
395 (*res)->idEntries[i].ResInfo.cursor.wWidth=bits->idEntries[i].bWidth;
396 (*res)->idEntries[i].ResInfo.cursor.wHeight=bits->idEntries[i].bHeight;
397 ((LPPOINT16)_free)->x=bits->idEntries[i].xHotspot;
398 ((LPPOINT16)_free)->y=bits->idEntries[i].yHotspot;
399 _free+=sizeof(POINT16);
400 } else {
401 (*res)->idEntries[i].ResInfo.icon.bWidth=bits->idEntries[i].bWidth;
402 (*res)->idEntries[i].ResInfo.icon.bHeight=bits->idEntries[i].bHeight;
403 (*res)->idEntries[i].ResInfo.icon.bColorCount = bits->idEntries[i].bColorCount;
405 (*res)->idEntries[i].wPlanes=1;
406 (*res)->idEntries[i].wBitCount = ((LPBITMAPINFOHEADER)((LPBYTE)bits +
407 bits->idEntries[i].dwDIBOffset))->biBitCount;
408 (*res)->idEntries[i].dwBytesInRes = bits->idEntries[i].dwDIBSize;
409 (*res)->idEntries[i].wResId=i+1;
411 memcpy(_free,(LPBYTE)bits +bits->idEntries[i].dwDIBOffset,
412 (*res)->idEntries[i].dwBytesInRes);
413 _free += (*res)->idEntries[i].dwBytesInRes;
415 UnmapViewOfFile( bits );
416 return TRUE;
417 fail:
418 if (*res) HeapFree( GetProcessHeap(), 0, *res );
419 if (*ptr) HeapFree( GetProcessHeap(), 0, *ptr );
420 UnmapViewOfFile( bits );
421 return FALSE;
425 /**********************************************************************
426 * CURSORICON_CreateFromResource
428 * Create a cursor or icon from in-memory resource template.
430 * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
431 * with cbSize parameter as well.
433 static HGLOBAL16 CURSORICON_CreateFromResource( HINSTANCE16 hInstance, HGLOBAL16 hObj, LPBYTE bits,
434 UINT cbSize, BOOL bIcon, DWORD dwVersion,
435 INT width, INT height, UINT loadflags )
437 int sizeAnd, sizeXor;
438 HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
439 BITMAPOBJ *bmpXor, *bmpAnd;
440 POINT16 hotspot;
441 BITMAPINFO *bmi;
442 HDC hdc;
443 BOOL DoStretch;
444 INT size;
446 hotspot.x = ICON_HOTSPOT;
447 hotspot.y = ICON_HOTSPOT;
449 TRACE_(cursor)("%08x (%u bytes), ver %08x, %ix%i %s %s\n",
450 (unsigned)bits, cbSize, (unsigned)dwVersion, width, height,
451 bIcon ? "icon" : "cursor", (loadflags & LR_MONOCHROME) ? "mono" : "" );
452 if (dwVersion == 0x00020000)
454 FIXME_(cursor)("\t2.xx resources are not supported\n");
455 return 0;
458 if (bIcon)
459 bmi = (BITMAPINFO *)bits;
460 else /* get the hotspot */
462 POINT16 *pt = (POINT16 *)bits;
463 hotspot = *pt;
464 bmi = (BITMAPINFO *)(pt + 1);
466 size = DIB_BitmapInfoSize( bmi, DIB_RGB_COLORS );
468 if (!width) width = bmi->bmiHeader.biWidth;
469 if (!height) height = bmi->bmiHeader.biHeight/2;
470 DoStretch = (bmi->bmiHeader.biHeight/2 != height) ||
471 (bmi->bmiHeader.biWidth != width);
473 /* Check bitmap header */
475 if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
476 (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) ||
477 bmi->bmiHeader.biCompression != BI_RGB) )
479 WARN_(cursor)("\tinvalid resource bitmap header.\n");
480 return 0;
483 if( (hdc = GetDC( 0 )) )
485 BITMAPINFO* pInfo;
487 /* Make sure we have room for the monochrome bitmap later on.
488 * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
489 * up to and including the biBitCount. In-memory icon resource
490 * format is as follows:
492 * BITMAPINFOHEADER icHeader // DIB header
493 * RGBQUAD icColors[] // Color table
494 * BYTE icXOR[] // DIB bits for XOR mask
495 * BYTE icAND[] // DIB bits for AND mask
498 if ((pInfo = (BITMAPINFO *)HeapAlloc( GetProcessHeap(), 0,
499 MAX(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))))
501 memcpy( pInfo, bmi, size );
502 pInfo->bmiHeader.biHeight /= 2;
504 /* Create the XOR bitmap */
506 if (DoStretch) {
507 if(bIcon)
509 hXorBits = CreateCompatibleBitmap(hdc, width, height);
511 else
513 hXorBits = CreateBitmap(width, height, 1, 1, NULL);
515 if(hXorBits)
517 HBITMAP hOld;
518 HDC hMem = CreateCompatibleDC(hdc);
519 BOOL res;
521 if (hMem) {
522 hOld = SelectObject(hMem, hXorBits);
523 res = StretchDIBits(hMem, 0, 0, width, height, 0, 0,
524 bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2,
525 (char*)bmi + size, pInfo, DIB_RGB_COLORS, SRCCOPY);
526 SelectObject(hMem, hOld);
527 DeleteDC(hMem);
528 } else res = FALSE;
529 if (!res) { DeleteObject(hXorBits); hXorBits = 0; }
531 } else hXorBits = CreateDIBitmap( hdc, &pInfo->bmiHeader,
532 CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS );
533 if( hXorBits )
535 char* bits = (char *)bmi + size +
536 DIB_GetDIBImageBytes(bmi->bmiHeader.biWidth,
537 bmi->bmiHeader.biHeight,
538 bmi->bmiHeader.biBitCount) / 2;
540 pInfo->bmiHeader.biBitCount = 1;
541 if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
543 RGBQUAD *rgb = pInfo->bmiColors;
545 pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
546 rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
547 rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
548 rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
550 else
552 RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
554 rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
555 rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
558 /* Create the AND bitmap */
560 if (DoStretch) {
561 if ((hAndBits = CreateBitmap(width, height, 1, 1, NULL))) {
562 HBITMAP hOld;
563 HDC hMem = CreateCompatibleDC(hdc);
564 BOOL res;
566 if (hMem) {
567 hOld = SelectObject(hMem, hAndBits);
568 res = StretchDIBits(hMem, 0, 0, width, height, 0, 0,
569 pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight,
570 bits, pInfo, DIB_RGB_COLORS, SRCCOPY);
571 SelectObject(hMem, hOld);
572 DeleteDC(hMem);
573 } else res = FALSE;
574 if (!res) { DeleteObject(hAndBits); hAndBits = 0; }
576 } else hAndBits = CreateDIBitmap( hdc, &pInfo->bmiHeader,
577 CBM_INIT, bits, pInfo, DIB_RGB_COLORS );
579 if( !hAndBits ) DeleteObject( hXorBits );
581 HeapFree( GetProcessHeap(), 0, pInfo );
583 ReleaseDC( 0, hdc );
586 if( !hXorBits || !hAndBits )
588 WARN_(cursor)("\tunable to create an icon bitmap.\n");
589 return 0;
592 /* Now create the CURSORICONINFO structure */
593 bmpXor = (BITMAPOBJ *) GDI_GetObjPtr( hXorBits, BITMAP_MAGIC );
594 bmpAnd = (BITMAPOBJ *) GDI_GetObjPtr( hAndBits, BITMAP_MAGIC );
595 sizeXor = bmpXor->bitmap.bmHeight * bmpXor->bitmap.bmWidthBytes;
596 sizeAnd = bmpAnd->bitmap.bmHeight * bmpAnd->bitmap.bmWidthBytes;
598 if (hObj) hObj = GlobalReAlloc16( hObj,
599 sizeof(CURSORICONINFO) + sizeXor + sizeAnd, GMEM_MOVEABLE );
600 if (!hObj) hObj = GlobalAlloc16( GMEM_MOVEABLE,
601 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
602 if (hObj)
604 CURSORICONINFO *info;
606 /* Make it owned by the module */
607 if (hInstance) FarSetOwner16( hObj, GetExePtr(hInstance) );
609 info = (CURSORICONINFO *)GlobalLock16( hObj );
610 info->ptHotSpot.x = hotspot.x;
611 info->ptHotSpot.y = hotspot.y;
612 info->nWidth = bmpXor->bitmap.bmWidth;
613 info->nHeight = bmpXor->bitmap.bmHeight;
614 info->nWidthBytes = bmpXor->bitmap.bmWidthBytes;
615 info->bPlanes = bmpXor->bitmap.bmPlanes;
616 info->bBitsPerPixel = bmpXor->bitmap.bmBitsPixel;
618 /* Transfer the bitmap bits to the CURSORICONINFO structure */
620 GetBitmapBits( hAndBits, sizeAnd, (char *)(info + 1) );
621 GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
622 GlobalUnlock16( hObj );
625 DeleteObject( hXorBits );
626 DeleteObject( hAndBits );
627 return hObj;
631 /**********************************************************************
632 * CreateIconFromResourceEx16 (USER.450)
634 * FIXME: not sure about exact parameter types
636 HICON16 WINAPI CreateIconFromResourceEx16( LPBYTE bits, UINT16 cbSize, BOOL16 bIcon,
637 DWORD dwVersion, INT16 width, INT16 height, UINT16 cFlag )
639 return CreateIconFromResourceEx(bits, cbSize, bIcon, dwVersion,
640 width, height, cFlag);
644 /**********************************************************************
645 * CreateIconFromResource (USER32.76)
647 HICON WINAPI CreateIconFromResource( LPBYTE bits, UINT cbSize,
648 BOOL bIcon, DWORD dwVersion)
650 return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
654 /**********************************************************************
655 * CreateIconFromResourceEx32 (USER32.77)
657 HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
658 BOOL bIcon, DWORD dwVersion,
659 INT width, INT height,
660 UINT cFlag )
662 TDB* pTask = (TDB*)GlobalLock16( GetCurrentTask() );
663 if( pTask )
664 return CURSORICON_CreateFromResource( pTask->hInstance, 0, bits, cbSize, bIcon, dwVersion,
665 width, height, cFlag );
666 return 0;
669 /**********************************************************************
670 * CURSORICON_Load
672 * Load a cursor or icon from resource or file.
674 HGLOBAL CURSORICON_Load( HINSTANCE hInstance, LPCWSTR name,
675 INT width, INT height, INT colors,
676 BOOL fCursor, UINT loadflags )
678 HANDLE handle = 0, h = 0;
679 HANDLE hRsrc;
680 CURSORICONDIR *dir;
681 CURSORICONDIRENTRY *dirEntry;
682 LPBYTE bits;
684 if ( loadflags & LR_LOADFROMFILE ) /* Load from file */
686 LPBYTE *ptr;
687 if (!CURSORICON_SimulateLoadingFromResourceW((LPWSTR)name, fCursor, &dir, &ptr))
688 return 0;
689 if (fCursor)
690 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(dir, width, height, 1);
691 else
692 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(dir, width, height, colors);
693 bits = ptr[dirEntry->wResId-1];
694 h = CURSORICON_CreateFromResource( 0, 0, bits, dirEntry->dwBytesInRes,
695 !fCursor, 0x00030000, width, height, loadflags);
696 HeapFree( GetProcessHeap(), 0, dir );
697 HeapFree( GetProcessHeap(), 0, ptr );
700 else if ( !hInstance ) /* Load OEM cursor/icon */
702 WORD resid;
703 HDC hdc;
705 if ( HIWORD(name) )
707 LPSTR ansi = HEAP_strdupWtoA(GetProcessHeap(),0,name);
708 if( ansi[0]=='#') /*Check for '#xxx' name */
710 resid = atoi(ansi+1);
711 HeapFree( GetProcessHeap(), 0, ansi );
713 else
715 HeapFree( GetProcessHeap(), 0, ansi );
716 return 0;
719 else resid = LOWORD(name);
720 hdc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
721 if (hdc) {
722 DC *dc = DC_GetDCPtr( hdc );
723 if (dc->funcs->pLoadOEMResource)
724 h = dc->funcs->pLoadOEMResource( resid, fCursor ? OEM_CURSOR : OEM_ICON );
725 GDI_HEAP_UNLOCK( hdc );
726 DeleteDC( hdc );
730 else /* Load from resource */
732 HANDLE hGroupRsrc;
733 WORD wResId;
734 DWORD dwBytesInRes;
736 /* Normalize hInstance (must be uniquely represented for icon cache) */
738 if ( HIWORD( hInstance ) )
739 hInstance = MapHModuleLS( hInstance );
740 else
741 hInstance = GetExePtr( hInstance );
743 /* Get directory resource ID */
745 if (!(hRsrc = FindResourceW( hInstance, name,
746 fCursor ? RT_GROUP_CURSORW : RT_GROUP_ICONW )))
747 return 0;
748 hGroupRsrc = hRsrc;
749 /* If shared icon, check whether it was already loaded */
751 if ( (loadflags & LR_SHARED)
752 && (h = CURSORICON_FindSharedIcon( hInstance, hRsrc ) ) != 0 )
753 return h;
755 /* Find the best entry in the directory */
757 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
758 if (!(dir = (CURSORICONDIR*)LockResource( handle ))) return 0;
759 if (fCursor)
760 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor( dir,
761 width, height, 1);
762 else
763 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon( dir,
764 width, height, colors );
765 if (!dirEntry) return 0;
766 wResId = dirEntry->wResId;
767 dwBytesInRes = dirEntry->dwBytesInRes;
768 FreeResource( handle );
770 /* Load the resource */
772 if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
773 fCursor ? RT_CURSORW : RT_ICONW ))) return 0;
774 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
775 bits = (LPBYTE)LockResource( handle );
776 h = CURSORICON_CreateFromResource( 0, 0, bits, dwBytesInRes,
777 !fCursor, 0x00030000, width, height, loadflags);
778 FreeResource( handle );
780 /* If shared icon, add to icon cache */
782 if ( h && (loadflags & LR_SHARED) )
783 CURSORICON_AddSharedIcon( hInstance, hRsrc, hGroupRsrc, h );
786 return h;
789 /***********************************************************************
790 * CURSORICON_Copy
792 * Make a copy of a cursor or icon.
794 static HGLOBAL16 CURSORICON_Copy( HINSTANCE16 hInstance, HGLOBAL16 handle )
796 char *ptrOld, *ptrNew;
797 int size;
798 HGLOBAL16 hNew;
800 if (!(ptrOld = (char *)GlobalLock16( handle ))) return 0;
801 if (!(hInstance = GetExePtr( hInstance ))) return 0;
802 size = GlobalSize16( handle );
803 hNew = GlobalAlloc16( GMEM_MOVEABLE, size );
804 FarSetOwner16( hNew, hInstance );
805 ptrNew = (char *)GlobalLock16( hNew );
806 memcpy( ptrNew, ptrOld, size );
807 GlobalUnlock16( handle );
808 GlobalUnlock16( hNew );
809 return hNew;
812 /*************************************************************************
813 * CURSORICON_ExtCopy
815 * Copies an Image from the Cache if LR_COPYFROMRESOURCE is specified
817 * PARAMS
818 * Handle [I] handle to an Image
819 * nType [I] Type of Handle (IMAGE_CURSOR | IMAGE_ICON)
820 * iDesiredCX [I] The Desired width of the Image
821 * iDesiredCY [I] The desired height of the Image
822 * nFlags [I] The flags from CopyImage
824 * RETURNS
825 * Success: The new handle of the Image
827 * NOTES
828 * LR_COPYDELETEORG and LR_MONOCHROME are currently not implemented.
829 * LR_MONOCHROME should be implemented by CURSORICON_CreateFromResource.
830 * LR_COPYFROMRESOURCE will only work if the Image is in the Cache.
835 HGLOBAL CURSORICON_ExtCopy(HGLOBAL Handle, UINT nType,
836 INT iDesiredCX, INT iDesiredCY,
837 UINT nFlags)
839 HGLOBAL16 hNew=0;
841 TRACE_(icon)("Handle %u, uType %u, iDesiredCX %i, iDesiredCY %i, nFlags %u\n",
842 Handle, nType, iDesiredCX, iDesiredCY, nFlags);
844 if(Handle == 0)
846 return 0;
849 /* Best Fit or Monochrome */
850 if( (nFlags & LR_COPYFROMRESOURCE
851 && (iDesiredCX > 0 || iDesiredCY > 0))
852 || nFlags & LR_MONOCHROME)
854 ICONCACHE* pIconCache = CURSORICON_FindCache(Handle);
856 /* Not Found in Cache, then do a strait copy
858 if(pIconCache == NULL)
860 TDB* pTask = (TDB *) GlobalLock16 (GetCurrentTask ());
861 hNew = CURSORICON_Copy(pTask->hInstance, Handle);
862 if(nFlags & LR_COPYFROMRESOURCE)
864 TRACE_(icon)("LR_COPYFROMRESOURCE: Failed to load from cache\n");
867 else
869 int iTargetCX, iTargetCY;
870 LPBYTE pBits;
871 HANDLE hMem;
872 HRSRC hRsrc;
873 DWORD dwBytesInRes;
874 WORD wResId;
875 CURSORICONDIR *pDir;
876 CURSORICONDIRENTRY *pDirEntry;
877 BOOL bIsIcon = (nType == IMAGE_ICON);
879 /* Completing iDesiredCX CY for Monochrome Bitmaps if needed
881 if(((nFlags & LR_MONOCHROME) && !(nFlags & LR_COPYFROMRESOURCE))
882 || (iDesiredCX == 0 && iDesiredCY == 0))
884 iDesiredCY = GetSystemMetrics(bIsIcon ?
885 SM_CYICON : SM_CYCURSOR);
886 iDesiredCX = GetSystemMetrics(bIsIcon ?
887 SM_CXICON : SM_CXCURSOR);
890 /* Retreive the CURSORICONDIRENTRY
892 if (!(hMem = LoadResource( pIconCache->hModule ,
893 pIconCache->hGroupRsrc)))
895 return 0;
897 if (!(pDir = (CURSORICONDIR*)LockResource( hMem )))
899 return 0;
902 /* Find Best Fit
904 if(bIsIcon)
906 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(
907 pDir, iDesiredCX, iDesiredCY, 256);
909 else
911 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(
912 pDir, iDesiredCX, iDesiredCY, 1);
915 wResId = pDirEntry->wResId;
916 dwBytesInRes = pDirEntry->dwBytesInRes;
917 FreeResource(hMem);
919 TRACE_(icon)("ResID %u, BytesInRes %lu, Width %d, Height %d DX %d, DY %d\n",
920 wResId, dwBytesInRes, pDirEntry->ResInfo.icon.bWidth,
921 pDirEntry->ResInfo.icon.bHeight, iDesiredCX, iDesiredCY);
923 /* Get the Best Fit
925 if (!(hRsrc = FindResourceW(pIconCache->hModule ,
926 MAKEINTRESOURCEW(wResId), bIsIcon ? RT_ICONW : RT_CURSORW)))
928 return 0;
930 if (!(hMem = LoadResource( pIconCache->hModule , hRsrc )))
932 return 0;
935 pBits = (LPBYTE)LockResource( hMem );
937 iTargetCY = GetSystemMetrics(SM_CYICON);
938 iTargetCX = GetSystemMetrics(SM_CXICON);
940 /* Create a New Icon with the proper dimension
942 hNew = CURSORICON_CreateFromResource( 0, 0, pBits, dwBytesInRes,
943 bIsIcon, 0x00030000, iTargetCX, iTargetCY, nFlags);
944 FreeResource(hMem);
947 else
949 TDB* pTask = (TDB *) GlobalLock16 (GetCurrentTask ());
950 hNew = CURSORICON_Copy(pTask->hInstance, Handle);
952 return hNew;
955 /***********************************************************************
956 * CURSORICON_IconToCursor
958 * Converts bitmap to mono and truncates if icon is too large (should
959 * probably do StretchBlt() instead).
961 HCURSOR16 CURSORICON_IconToCursor(HICON16 hIcon, BOOL bSemiTransparent)
963 HCURSOR16 hRet = 0;
964 CURSORICONINFO *pIcon = NULL;
965 HTASK16 hTask = GetCurrentTask();
966 TDB* pTask = (TDB *)GlobalLock16(hTask);
968 if(hIcon && pTask)
969 if (!(pIcon = (CURSORICONINFO*)GlobalLock16( hIcon ))) return FALSE;
970 if (pIcon->bPlanes * pIcon->bBitsPerPixel == 1)
972 hRet = CURSORICON_Copy( pTask->hInstance, hIcon );
975 pIcon = GlobalLock16(hRet);
977 pIcon->ptHotSpot.x = pIcon->ptHotSpot.y = 15;
979 GlobalUnlock(hRet);
981 else
983 BYTE pAndBits[128];
984 BYTE pXorBits[128];
985 int maxx, maxy, ix, iy, bpp = pIcon->bBitsPerPixel;
986 BYTE* psPtr, *pxbPtr = pXorBits;
987 unsigned xor_width, and_width, val_base = 0xffffffff >> (32 - bpp);
988 BYTE* pbc = NULL;
990 CURSORICONINFO cI;
992 TRACE_(icon)("[%04x] %ix%i %ibpp (bogus %ibps)\n",
993 hIcon, pIcon->nWidth, pIcon->nHeight, pIcon->bBitsPerPixel, pIcon->nWidthBytes );
995 xor_width = BITMAP_GetWidthBytes( pIcon->nWidth, bpp );
996 and_width = BITMAP_GetWidthBytes( pIcon->nWidth, 1 );
997 psPtr = (BYTE *)(pIcon + 1) + pIcon->nHeight * and_width;
999 memset(pXorBits, 0, 128);
1000 cI.bBitsPerPixel = 1; cI.bPlanes = 1;
1001 cI.ptHotSpot.x = cI.ptHotSpot.y = 15;
1002 cI.nWidth = 32; cI.nHeight = 32;
1003 cI.nWidthBytes = 4; /* 32x1bpp */
1005 maxx = (pIcon->nWidth > 32) ? 32 : pIcon->nWidth;
1006 maxy = (pIcon->nHeight > 32) ? 32 : pIcon->nHeight;
1008 for( iy = 0; iy < maxy; iy++ )
1010 unsigned shift = iy % 2;
1012 memcpy( pAndBits + iy * 4, (BYTE *)(pIcon + 1) + iy * and_width,
1013 (and_width > 4) ? 4 : and_width );
1014 for( ix = 0; ix < maxx; ix++ )
1016 if( bSemiTransparent && ((ix+shift)%2) )
1018 /* set AND bit, XOR bit stays 0 */
1020 pbc = pAndBits + iy * 4 + ix/8;
1021 *pbc |= 0x80 >> (ix%8);
1023 else
1025 /* keep AND bit, set XOR bit */
1027 unsigned *psc = (unsigned*)(psPtr + (ix * bpp)/8);
1028 unsigned val = ((*psc) >> (ix * bpp)%8) & val_base;
1029 if(!PALETTE_Driver->pIsDark(val))
1031 pbc = pxbPtr + ix/8;
1032 *pbc |= 0x80 >> (ix%8);
1036 psPtr += xor_width;
1037 pxbPtr += 4;
1040 hRet = CreateCursorIconIndirect16( pTask->hInstance , &cI, pAndBits, pXorBits);
1042 if( !hRet ) /* fall back on default drag cursor */
1043 hRet = CURSORICON_Copy( pTask->hInstance ,
1044 CURSORICON_Load(0,MAKEINTRESOURCEW(OCR_DRAGOBJECT),
1045 GetSystemMetrics(SM_CXCURSOR),
1046 GetSystemMetrics(SM_CYCURSOR), 1, TRUE, 0) );
1049 return hRet;
1053 /***********************************************************************
1054 * LoadCursor16 (USER.173)
1056 HCURSOR16 WINAPI LoadCursor16( HINSTANCE16 hInstance, SEGPTR name )
1058 LPCSTR nameStr = HIWORD(name)? PTR_SEG_TO_LIN(name) : (LPCSTR)name;
1059 return LoadCursorA( hInstance, nameStr );
1063 /***********************************************************************
1064 * LoadIcon16 (USER.174)
1066 HICON16 WINAPI LoadIcon16( HINSTANCE16 hInstance, SEGPTR name )
1068 LPCSTR nameStr = HIWORD(name)? PTR_SEG_TO_LIN(name) : (LPCSTR)name;
1069 return LoadIconA( hInstance, nameStr );
1073 /***********************************************************************
1074 * CreateCursor16 (USER.406)
1076 HCURSOR16 WINAPI CreateCursor16( HINSTANCE16 hInstance,
1077 INT16 xHotSpot, INT16 yHotSpot,
1078 INT16 nWidth, INT16 nHeight,
1079 LPCVOID lpANDbits, LPCVOID lpXORbits )
1081 CURSORICONINFO info;
1083 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1084 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1086 info.ptHotSpot.x = xHotSpot;
1087 info.ptHotSpot.y = yHotSpot;
1088 info.nWidth = nWidth;
1089 info.nHeight = nHeight;
1090 info.nWidthBytes = 0;
1091 info.bPlanes = 1;
1092 info.bBitsPerPixel = 1;
1094 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1098 /***********************************************************************
1099 * CreateCursor32 (USER32.67)
1101 HCURSOR WINAPI CreateCursor( HINSTANCE hInstance,
1102 INT xHotSpot, INT yHotSpot,
1103 INT nWidth, INT nHeight,
1104 LPCVOID lpANDbits, LPCVOID lpXORbits )
1106 CURSORICONINFO info;
1108 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1109 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1111 info.ptHotSpot.x = xHotSpot;
1112 info.ptHotSpot.y = yHotSpot;
1113 info.nWidth = nWidth;
1114 info.nHeight = nHeight;
1115 info.nWidthBytes = 0;
1116 info.bPlanes = 1;
1117 info.bBitsPerPixel = 1;
1119 return CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
1123 /***********************************************************************
1124 * CreateIcon16 (USER.407)
1126 HICON16 WINAPI CreateIcon16( HINSTANCE16 hInstance, INT16 nWidth,
1127 INT16 nHeight, BYTE bPlanes, BYTE bBitsPixel,
1128 LPCVOID lpANDbits, LPCVOID lpXORbits )
1130 CURSORICONINFO info;
1132 TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1133 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1135 info.ptHotSpot.x = ICON_HOTSPOT;
1136 info.ptHotSpot.y = ICON_HOTSPOT;
1137 info.nWidth = nWidth;
1138 info.nHeight = nHeight;
1139 info.nWidthBytes = 0;
1140 info.bPlanes = bPlanes;
1141 info.bBitsPerPixel = bBitsPixel;
1143 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1147 /***********************************************************************
1148 * CreateIcon32 (USER32.75)
1150 HICON WINAPI CreateIcon( HINSTANCE hInstance, INT nWidth,
1151 INT nHeight, BYTE bPlanes, BYTE bBitsPixel,
1152 LPCVOID lpANDbits, LPCVOID lpXORbits )
1154 CURSORICONINFO info;
1156 TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1157 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1159 info.ptHotSpot.x = ICON_HOTSPOT;
1160 info.ptHotSpot.y = ICON_HOTSPOT;
1161 info.nWidth = nWidth;
1162 info.nHeight = nHeight;
1163 info.nWidthBytes = 0;
1164 info.bPlanes = bPlanes;
1165 info.bBitsPerPixel = bBitsPixel;
1167 return CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
1171 /***********************************************************************
1172 * CreateCursorIconIndirect (USER.408)
1174 HGLOBAL16 WINAPI CreateCursorIconIndirect16( HINSTANCE16 hInstance,
1175 CURSORICONINFO *info,
1176 LPCVOID lpANDbits,
1177 LPCVOID lpXORbits )
1179 HGLOBAL16 handle;
1180 char *ptr;
1181 int sizeAnd, sizeXor;
1183 hInstance = GetExePtr( hInstance ); /* Make it a module handle */
1184 if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
1185 info->nWidthBytes = BITMAP_GetWidthBytes(info->nWidth,info->bBitsPerPixel);
1186 sizeXor = info->nHeight * info->nWidthBytes;
1187 sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
1188 if (!(handle = GlobalAlloc16( GMEM_MOVEABLE,
1189 sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
1190 return 0;
1191 if (hInstance) FarSetOwner16( handle, hInstance );
1192 ptr = (char *)GlobalLock16( handle );
1193 memcpy( ptr, info, sizeof(*info) );
1194 memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
1195 memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
1196 GlobalUnlock16( handle );
1197 return handle;
1201 /***********************************************************************
1202 * CopyIcon16 (USER.368)
1204 HICON16 WINAPI CopyIcon16( HINSTANCE16 hInstance, HICON16 hIcon )
1206 TRACE_(icon)("%04x %04x\n", hInstance, hIcon );
1207 return CURSORICON_Copy( hInstance, hIcon );
1211 /***********************************************************************
1212 * CopyIcon32 (USER32.60)
1214 HICON WINAPI CopyIcon( HICON hIcon )
1216 HTASK16 hTask = GetCurrentTask ();
1217 TDB* pTask = (TDB *) GlobalLock16 (hTask);
1218 TRACE_(icon)("%04x\n", hIcon );
1219 return CURSORICON_Copy( pTask->hInstance, hIcon );
1223 /***********************************************************************
1224 * CopyCursor16 (USER.369)
1226 HCURSOR16 WINAPI CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
1228 TRACE_(cursor)("%04x %04x\n", hInstance, hCursor );
1229 return CURSORICON_Copy( hInstance, hCursor );
1232 /**********************************************************************
1233 * CURSORICON_Destroy (USER.610)
1235 * This routine is actually exported from Win95 USER under the name
1236 * DestroyIcon32 ... The behaviour implemented here should mimic
1237 * the Win95 one exactly, especially the return values, which
1238 * depend on the setting of various flags.
1240 WORD WINAPI CURSORICON_Destroy( HGLOBAL16 handle, UINT16 flags )
1242 WORD retv;
1244 TRACE_(icon)("(%04x, %04x)\n", handle, flags );
1246 /* Check whether destroying active cursor */
1248 if ( hActiveCursor == handle )
1250 ERR_(cursor)("Destroying active cursor!\n" );
1251 SetCursor( 0 );
1254 /* Try shared cursor/icon first */
1256 if ( !(flags & CID_NONSHARED) )
1258 INT count = CURSORICON_DelSharedIcon( handle );
1260 if ( count != -1 )
1261 return (flags & CID_WIN32)? TRUE : (count == 0);
1263 /* FIXME: OEM cursors/icons should be recognized */
1266 /* Now assume non-shared cursor/icon */
1268 retv = GlobalFree16( handle );
1269 return (flags & CID_RESOURCE)? retv : TRUE;
1272 /***********************************************************************
1273 * DestroyIcon16 (USER.457)
1275 BOOL16 WINAPI DestroyIcon16( HICON16 hIcon )
1277 return CURSORICON_Destroy( hIcon, 0 );
1280 /***********************************************************************
1281 * DestroyIcon (USER32.133)
1283 BOOL WINAPI DestroyIcon( HICON hIcon )
1285 return CURSORICON_Destroy( hIcon, CID_WIN32 );
1288 /***********************************************************************
1289 * DestroyCursor16 (USER.458)
1291 BOOL16 WINAPI DestroyCursor16( HCURSOR16 hCursor )
1293 return CURSORICON_Destroy( hCursor, 0 );
1296 /***********************************************************************
1297 * DestroyCursor (USER32.132)
1299 BOOL WINAPI DestroyCursor( HCURSOR hCursor )
1301 return CURSORICON_Destroy( hCursor, CID_WIN32 );
1305 /***********************************************************************
1306 * DrawIcon16 (USER.84)
1308 BOOL16 WINAPI DrawIcon16( HDC16 hdc, INT16 x, INT16 y, HICON16 hIcon )
1310 return DrawIcon( hdc, x, y, hIcon );
1314 /***********************************************************************
1315 * DrawIcon32 (USER32.159)
1317 BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
1319 CURSORICONINFO *ptr;
1320 HDC hMemDC;
1321 HBITMAP hXorBits, hAndBits;
1322 COLORREF oldFg, oldBg;
1324 if (!(ptr = (CURSORICONINFO *)GlobalLock16( hIcon ))) return FALSE;
1325 if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
1326 hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1,
1327 (char *)(ptr+1) );
1328 hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
1329 ptr->bBitsPerPixel, (char *)(ptr + 1)
1330 + ptr->nHeight * BITMAP_GetWidthBytes(ptr->nWidth,1) );
1331 oldFg = SetTextColor( hdc, RGB(0,0,0) );
1332 oldBg = SetBkColor( hdc, RGB(255,255,255) );
1334 if (hXorBits && hAndBits)
1336 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1337 BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
1338 SelectObject( hMemDC, hXorBits );
1339 BitBlt(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
1340 SelectObject( hMemDC, hBitTemp );
1342 DeleteDC( hMemDC );
1343 if (hXorBits) DeleteObject( hXorBits );
1344 if (hAndBits) DeleteObject( hAndBits );
1345 GlobalUnlock16( hIcon );
1346 SetTextColor( hdc, oldFg );
1347 SetBkColor( hdc, oldBg );
1348 return TRUE;
1352 /***********************************************************************
1353 * DumpIcon (USER.459)
1355 DWORD WINAPI DumpIcon16( SEGPTR pInfo, WORD *lpLen,
1356 SEGPTR *lpXorBits, SEGPTR *lpAndBits )
1358 CURSORICONINFO *info = PTR_SEG_TO_LIN( pInfo );
1359 int sizeAnd, sizeXor;
1361 if (!info) return 0;
1362 sizeXor = info->nHeight * info->nWidthBytes;
1363 sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
1364 if (lpAndBits) *lpAndBits = pInfo + sizeof(CURSORICONINFO);
1365 if (lpXorBits) *lpXorBits = pInfo + sizeof(CURSORICONINFO) + sizeAnd;
1366 if (lpLen) *lpLen = sizeof(CURSORICONINFO) + sizeAnd + sizeXor;
1367 return MAKELONG( sizeXor, sizeXor );
1371 /***********************************************************************
1372 * SetCursor16 (USER.69)
1374 HCURSOR16 WINAPI SetCursor16( HCURSOR16 hCursor )
1376 return (HCURSOR16)SetCursor( hCursor );
1380 /***********************************************************************
1381 * SetCursor32 (USER32.472)
1382 * RETURNS:
1383 * A handle to the previous cursor shape.
1385 HCURSOR WINAPI SetCursor(
1386 HCURSOR hCursor /* Handle of cursor to show */
1388 HCURSOR hOldCursor;
1390 if (hCursor == hActiveCursor) return hActiveCursor; /* No change */
1391 TRACE_(cursor)("%04x\n", hCursor );
1392 hOldCursor = hActiveCursor;
1393 hActiveCursor = hCursor;
1394 /* Change the cursor shape only if it is visible */
1395 if (CURSOR_ShowCount >= 0)
1397 DISPLAY_SetCursor( (CURSORICONINFO*)GlobalLock16( hActiveCursor ) );
1398 GlobalUnlock16( hActiveCursor );
1400 return hOldCursor;
1404 /***********************************************************************
1405 * SetCursorPos16 (USER.70)
1407 void WINAPI SetCursorPos16( INT16 x, INT16 y )
1409 SetCursorPos( x, y );
1413 /***********************************************************************
1414 * SetCursorPos32 (USER32.474)
1416 BOOL WINAPI SetCursorPos( INT x, INT y )
1418 DISPLAY_MoveCursor( x, y );
1419 return TRUE;
1423 /***********************************************************************
1424 * ShowCursor16 (USER.71)
1426 INT16 WINAPI ShowCursor16( BOOL16 bShow )
1428 return ShowCursor( bShow );
1432 /***********************************************************************
1433 * ShowCursor32 (USER32.530)
1435 INT WINAPI ShowCursor( BOOL bShow )
1437 TRACE_(cursor)("%d, count=%d\n",
1438 bShow, CURSOR_ShowCount );
1440 if (bShow)
1442 if (++CURSOR_ShowCount == 0) /* Show it */
1444 DISPLAY_SetCursor((CURSORICONINFO*)GlobalLock16( hActiveCursor ));
1445 GlobalUnlock16( hActiveCursor );
1448 else
1450 if (--CURSOR_ShowCount == -1) /* Hide it */
1451 DISPLAY_SetCursor( NULL );
1453 return CURSOR_ShowCount;
1457 /***********************************************************************
1458 * GetCursor16 (USER.247)
1460 HCURSOR16 WINAPI GetCursor16(void)
1462 return hActiveCursor;
1466 /***********************************************************************
1467 * GetCursor32 (USER32.227)
1469 HCURSOR WINAPI GetCursor(void)
1471 return hActiveCursor;
1475 /***********************************************************************
1476 * ClipCursor16 (USER.16)
1478 BOOL16 WINAPI ClipCursor16( const RECT16 *rect )
1480 if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1481 else CONV_RECT16TO32( rect, &CURSOR_ClipRect );
1482 return TRUE;
1486 /***********************************************************************
1487 * ClipCursor32 (USER32.53)
1489 BOOL WINAPI ClipCursor( const RECT *rect )
1491 if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1492 else CopyRect( &CURSOR_ClipRect, rect );
1493 return TRUE;
1497 /***********************************************************************
1498 * GetCursorPos16 (USER.17)
1500 BOOL16 WINAPI GetCursorPos16( POINT16 *pt )
1502 if (!pt) return 0;
1504 pt->x = PosX;
1505 pt->y = PosY;
1507 TRACE_(cursor)("ret=%d,%d\n", pt->x, pt->y );
1508 return 1;
1512 /***********************************************************************
1513 * GetCursorPos32 (USER32.229)
1515 BOOL WINAPI GetCursorPos( POINT *pt )
1517 BOOL ret;
1519 POINT16 pt16;
1520 ret = GetCursorPos16( &pt16 );
1521 if (pt) CONV_POINT16TO32( &pt16, pt );
1522 return ((pt) ? ret : 0);
1526 /***********************************************************************
1527 * GetClipCursor16 (USER.309)
1529 void WINAPI GetClipCursor16( RECT16 *rect )
1531 if (rect) CONV_RECT32TO16( &CURSOR_ClipRect, rect );
1535 /***********************************************************************
1536 * GetClipCursor32 (USER32.221)
1538 BOOL WINAPI GetClipCursor( RECT *rect )
1540 if (rect)
1542 CopyRect( rect, &CURSOR_ClipRect );
1543 return TRUE;
1545 return FALSE;
1548 /**********************************************************************
1549 * LookupIconIdFromDirectoryEx16 (USER.364)
1551 * FIXME: exact parameter sizes
1553 INT16 WINAPI LookupIconIdFromDirectoryEx16( LPBYTE xdir, BOOL16 bIcon,
1554 INT16 width, INT16 height, UINT16 cFlag )
1556 CURSORICONDIR *dir = (CURSORICONDIR*)xdir;
1557 UINT16 retVal = 0;
1558 if( dir && !dir->idReserved && (dir->idType & 3) )
1560 CURSORICONDIRENTRY* entry;
1561 HDC hdc;
1562 UINT palEnts;
1563 int colors;
1564 hdc = GetDC(0);
1565 palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
1566 if (palEnts == 0)
1567 palEnts = 256;
1568 colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
1570 ReleaseDC(0, hdc);
1572 if( bIcon )
1573 entry = CURSORICON_FindBestIcon( dir, width, height, colors );
1574 else
1575 entry = CURSORICON_FindBestCursor( dir, width, height, 1);
1577 if( entry ) retVal = entry->wResId;
1579 else WARN_(cursor)("invalid resource directory\n");
1580 return retVal;
1583 /**********************************************************************
1584 * LookupIconIdFromDirectoryEx32 (USER32.380)
1586 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE dir, BOOL bIcon,
1587 INT width, INT height, UINT cFlag )
1589 return LookupIconIdFromDirectoryEx16( dir, bIcon, width, height, cFlag );
1592 /**********************************************************************
1593 * LookupIconIdFromDirectory (USER.???)
1595 INT16 WINAPI LookupIconIdFromDirectory16( LPBYTE dir, BOOL16 bIcon )
1597 return LookupIconIdFromDirectoryEx16( dir, bIcon,
1598 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1599 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1602 /**********************************************************************
1603 * LookupIconIdFromDirectory (USER32.379)
1605 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1607 return LookupIconIdFromDirectoryEx( dir, bIcon,
1608 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1609 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1612 /**********************************************************************
1613 * GetIconID (USER.455)
1615 WORD WINAPI GetIconID16( HGLOBAL16 hResource, DWORD resType )
1617 LPBYTE lpDir = (LPBYTE)GlobalLock16(hResource);
1619 TRACE_(cursor)("hRes=%04x, entries=%i\n",
1620 hResource, lpDir ? ((CURSORICONDIR*)lpDir)->idCount : 0);
1622 switch(resType)
1624 case RT_CURSOR16:
1625 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, FALSE,
1626 GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1627 case RT_ICON16:
1628 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, TRUE,
1629 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0 );
1630 default:
1631 WARN_(cursor)("invalid res type %ld\n", resType );
1633 return 0;
1636 /**********************************************************************
1637 * LoadCursorIconHandler (USER.336)
1639 * Supposed to load resources of Windows 2.x applications.
1641 HGLOBAL16 WINAPI LoadCursorIconHandler16( HGLOBAL16 hResource, HMODULE16 hModule, HRSRC16 hRsrc )
1643 FIXME_(cursor)("(%04x,%04x,%04x): old 2.x resources are not supported!\n",
1644 hResource, hModule, hRsrc);
1645 return (HGLOBAL16)0;
1648 /**********************************************************************
1649 * LoadDIBIconHandler (USER.357)
1651 * RT_ICON resource loader, installed by USER_SignalProc when module
1652 * is initialized.
1654 HGLOBAL16 WINAPI LoadDIBIconHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1656 /* If hResource is zero we must allocate a new memory block, if it's
1657 * non-zero but GlobalLock() returns NULL then it was discarded and
1658 * we have to recommit some memory, otherwise we just need to check
1659 * the block size. See LoadProc() in 16-bit SDK for more.
1662 hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1663 if( hMemObj )
1665 LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1666 hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1667 SizeofResource16(hModule, hRsrc), TRUE, 0x00030000,
1668 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR );
1670 return hMemObj;
1673 /**********************************************************************
1674 * LoadDIBCursorHandler (USER.356)
1676 * RT_CURSOR resource loader. Same as above.
1678 HGLOBAL16 WINAPI LoadDIBCursorHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1680 hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1681 if( hMemObj )
1683 LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1684 hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1685 SizeofResource16(hModule, hRsrc), FALSE, 0x00030000,
1686 GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1688 return hMemObj;
1691 /**********************************************************************
1692 * LoadIconHandler (USER.456)
1694 HICON16 WINAPI LoadIconHandler16( HGLOBAL16 hResource, BOOL16 bNew )
1696 LPBYTE bits = (LPBYTE)LockResource16( hResource );
1698 TRACE_(cursor)("hRes=%04x\n",hResource);
1700 return CURSORICON_CreateFromResource( 0, 0, bits, 0, TRUE,
1701 bNew ? 0x00030000 : 0x00020000, 0, 0, LR_DEFAULTCOLOR );
1704 /***********************************************************************
1705 * LoadCursorW (USER32.362)
1707 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
1709 return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0,
1710 LR_SHARED | LR_DEFAULTSIZE );
1713 /***********************************************************************
1714 * LoadCursorA (USER32.359)
1716 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
1718 return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0,
1719 LR_SHARED | LR_DEFAULTSIZE );
1722 /***********************************************************************
1723 * LoadCursorFromFileW (USER32.361)
1725 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
1727 return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0,
1728 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1731 /***********************************************************************
1732 * LoadCursorFromFileA (USER32.360)
1734 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
1736 return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0,
1737 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1740 /***********************************************************************
1741 * LoadIconW (USER32.364)
1743 HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
1745 return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0,
1746 LR_SHARED | LR_DEFAULTSIZE );
1749 /***********************************************************************
1750 * LoadIconA (USER32.363)
1752 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
1754 return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0,
1755 LR_SHARED | LR_DEFAULTSIZE );
1758 /**********************************************************************
1759 * GetIconInfo16 (USER.395)
1761 BOOL16 WINAPI GetIconInfo16(HICON16 hIcon,LPICONINFO16 iconinfo)
1763 ICONINFO ii32;
1764 BOOL16 ret = GetIconInfo((HICON)hIcon, &ii32);
1766 iconinfo->fIcon = ii32.fIcon;
1767 iconinfo->xHotspot = ii32.xHotspot;
1768 iconinfo->yHotspot = ii32.yHotspot;
1769 iconinfo->hbmMask = ii32.hbmMask;
1770 iconinfo->hbmColor = ii32.hbmColor;
1771 return ret;
1774 /**********************************************************************
1775 * GetIconInfo32 (USER32.242)
1777 BOOL WINAPI GetIconInfo(HICON hIcon,LPICONINFO iconinfo) {
1778 CURSORICONINFO *ciconinfo;
1780 ciconinfo = GlobalLock16(hIcon);
1781 if (!ciconinfo)
1782 return FALSE;
1784 if ( (ciconinfo->ptHotSpot.x == ICON_HOTSPOT) &&
1785 (ciconinfo->ptHotSpot.y == ICON_HOTSPOT) )
1787 iconinfo->fIcon = TRUE;
1788 iconinfo->xHotspot = 0;
1789 iconinfo->yHotspot = 0;
1791 else
1793 iconinfo->fIcon = FALSE;
1794 iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
1795 iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
1798 iconinfo->hbmColor = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1799 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
1800 (char *)(ciconinfo + 1)
1801 + ciconinfo->nHeight *
1802 BITMAP_GetWidthBytes (ciconinfo->nWidth,1) );
1803 iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1804 1, 1, (char *)(ciconinfo + 1));
1806 GlobalUnlock16(hIcon);
1808 return TRUE;
1811 /**********************************************************************
1812 * CreateIconIndirect (USER32.78)
1814 HICON WINAPI CreateIconIndirect(LPICONINFO iconinfo) {
1815 BITMAPOBJ *bmpXor,*bmpAnd;
1816 HICON hObj;
1817 int sizeXor,sizeAnd;
1819 bmpXor = (BITMAPOBJ *) GDI_GetObjPtr( iconinfo->hbmColor, BITMAP_MAGIC );
1820 bmpAnd = (BITMAPOBJ *) GDI_GetObjPtr( iconinfo->hbmMask, BITMAP_MAGIC );
1822 sizeXor = bmpXor->bitmap.bmHeight * bmpXor->bitmap.bmWidthBytes;
1823 sizeAnd = bmpAnd->bitmap.bmHeight * bmpAnd->bitmap.bmWidthBytes;
1825 hObj = GlobalAlloc16( GMEM_MOVEABLE,
1826 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
1827 if (hObj)
1829 CURSORICONINFO *info;
1831 info = (CURSORICONINFO *)GlobalLock16( hObj );
1833 /* If we are creating an icon, the hotspot is unused */
1834 if (iconinfo->fIcon)
1836 info->ptHotSpot.x = ICON_HOTSPOT;
1837 info->ptHotSpot.y = ICON_HOTSPOT;
1839 else
1841 info->ptHotSpot.x = iconinfo->xHotspot;
1842 info->ptHotSpot.y = iconinfo->yHotspot;
1845 info->nWidth = bmpXor->bitmap.bmWidth;
1846 info->nHeight = bmpXor->bitmap.bmHeight;
1847 info->nWidthBytes = bmpXor->bitmap.bmWidthBytes;
1848 info->bPlanes = bmpXor->bitmap.bmPlanes;
1849 info->bBitsPerPixel = bmpXor->bitmap.bmBitsPixel;
1851 /* Transfer the bitmap bits to the CURSORICONINFO structure */
1853 GetBitmapBits( iconinfo->hbmMask ,sizeAnd,(char*)(info + 1) );
1854 GetBitmapBits( iconinfo->hbmColor,sizeXor,(char*)(info + 1) +sizeAnd);
1855 GlobalUnlock16( hObj );
1857 return hObj;
1861 /**********************************************************************
1863 DrawIconEx16 (USER.394)
1865 BOOL16 WINAPI DrawIconEx16 (HDC16 hdc, INT16 xLeft, INT16 yTop, HICON16 hIcon,
1866 INT16 cxWidth, INT16 cyWidth, UINT16 istep,
1867 HBRUSH16 hbr, UINT16 flags)
1869 return DrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
1870 istep, hbr, flags);
1874 /******************************************************************************
1875 * DrawIconEx32 [USER32.160] Draws an icon or cursor on device context
1877 * NOTES
1878 * Why is this using SM_CXICON instead of SM_CXCURSOR?
1880 * PARAMS
1881 * hdc [I] Handle to device context
1882 * x0 [I] X coordinate of upper left corner
1883 * y0 [I] Y coordinate of upper left corner
1884 * hIcon [I] Handle to icon to draw
1885 * cxWidth [I] Width of icon
1886 * cyWidth [I] Height of icon
1887 * istep [I] Index of frame in animated cursor
1888 * hbr [I] Handle to background brush
1889 * flags [I] Icon-drawing flags
1891 * RETURNS
1892 * Success: TRUE
1893 * Failure: FALSE
1895 BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
1896 INT cxWidth, INT cyWidth, UINT istep,
1897 HBRUSH hbr, UINT flags )
1899 CURSORICONINFO *ptr = (CURSORICONINFO *)GlobalLock16 (hIcon);
1900 HDC hDC_off = 0, hMemDC = CreateCompatibleDC (hdc);
1901 BOOL result = FALSE, DoOffscreen = FALSE;
1902 HBITMAP hB_off = 0, hOld = 0;
1904 if (!ptr) return FALSE;
1906 if (istep)
1907 FIXME_(icon)("Ignoring istep=%d\n", istep);
1908 if (flags & DI_COMPAT)
1909 FIXME_(icon)("Ignoring flag DI_COMPAT\n");
1911 /* Calculate the size of the destination image. */
1912 if (cxWidth == 0)
1914 if (flags & DI_DEFAULTSIZE)
1915 cxWidth = GetSystemMetrics (SM_CXICON);
1916 else
1917 cxWidth = ptr->nWidth;
1919 if (cyWidth == 0)
1921 if (flags & DI_DEFAULTSIZE)
1922 cyWidth = GetSystemMetrics (SM_CYICON);
1923 else
1924 cyWidth = ptr->nHeight;
1927 if (!(DoOffscreen = (hbr >= STOCK_WHITE_BRUSH) && (hbr <=
1928 STOCK_HOLLOW_BRUSH)))
1930 GDIOBJHDR *object = (GDIOBJHDR *) GDI_HEAP_LOCK(hbr);
1931 if (object)
1933 UINT16 magic = object->wMagic;
1934 GDI_HEAP_UNLOCK(hbr);
1935 DoOffscreen = magic == BRUSH_MAGIC;
1938 if (DoOffscreen) {
1939 RECT r;
1941 r.left = 0;
1942 r.top = 0;
1943 r.right = cxWidth;
1944 r.bottom = cxWidth;
1946 hDC_off = CreateCompatibleDC(hdc);
1947 hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth);
1948 if (hDC_off && hB_off) {
1949 hOld = SelectObject(hDC_off, hB_off);
1950 FillRect(hDC_off, &r, hbr);
1954 if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
1956 HBITMAP hXorBits, hAndBits;
1957 COLORREF oldFg, oldBg;
1958 INT nStretchMode;
1960 nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
1962 hXorBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1963 ptr->bPlanes, ptr->bBitsPerPixel,
1964 (char *)(ptr + 1)
1965 + ptr->nHeight *
1966 BITMAP_GetWidthBytes(ptr->nWidth,1) );
1967 hAndBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1968 1, 1, (char *)(ptr+1) );
1969 oldFg = SetTextColor( hdc, RGB(0,0,0) );
1970 oldBg = SetBkColor( hdc, RGB(255,255,255) );
1972 if (hXorBits && hAndBits)
1974 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1975 if (flags & DI_MASK)
1977 if (DoOffscreen)
1978 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1979 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1980 else
1981 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
1982 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1984 SelectObject( hMemDC, hXorBits );
1985 if (flags & DI_IMAGE)
1987 if (DoOffscreen)
1988 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1989 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
1990 else
1991 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
1992 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
1994 SelectObject( hMemDC, hBitTemp );
1995 result = TRUE;
1998 SetTextColor( hdc, oldFg );
1999 SetBkColor( hdc, oldBg );
2000 if (hXorBits) DeleteObject( hXorBits );
2001 if (hAndBits) DeleteObject( hAndBits );
2002 SetStretchBltMode (hdc, nStretchMode);
2003 if (DoOffscreen) {
2004 BitBlt(hdc, x0, y0, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
2005 SelectObject(hDC_off, hOld);
2008 if (hMemDC) DeleteDC( hMemDC );
2009 if (hDC_off) DeleteDC(hDC_off);
2010 if (hB_off) DeleteObject(hB_off);
2011 GlobalUnlock16( hIcon );
2012 return result;