CURSORICON_IconToCursor: inconsistent Lock/Unlock
[wine.git] / objects / cursoricon.c
blob5b596864502904b30fe500b1a09667792cc8fc51
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 "display.h"
52 #include "message.h"
53 #include "winerror.h"
55 DECLARE_DEBUG_CHANNEL(cursor)
56 DECLARE_DEBUG_CHANNEL(icon)
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;
85 static DWORD ICON_HOTSPOT = 0x42424242;
87 /**********************************************************************
88 * CURSORICON_Init
90 void CURSORICON_Init( void )
92 InitializeCriticalSection( &IconCrst );
93 MakeCriticalSectionGlobal( &IconCrst );
96 /**********************************************************************
97 * CURSORICON_FindSharedIcon
99 static HANDLE CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
101 HANDLE handle = 0;
102 ICONCACHE *ptr;
104 EnterCriticalSection( &IconCrst );
106 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
107 if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
109 ptr->count++;
110 handle = ptr->handle;
111 break;
114 LeaveCriticalSection( &IconCrst );
116 return handle;
119 /*************************************************************************
120 * CURSORICON_FindCache
122 * Given a handle, find the coresponding cache element
124 * PARAMS
125 * Handle [I] handle to an Image
127 * RETURNS
128 * Success: The cache entry
129 * Failure: NULL
132 static ICONCACHE* CURSORICON_FindCache(HANDLE handle)
134 ICONCACHE *ptr;
135 ICONCACHE *pRet=NULL;
136 BOOL IsFound = FALSE;
137 int count;
139 EnterCriticalSection( &IconCrst );
141 for (count = 0, ptr = IconAnchor; ptr != NULL && !IsFound; ptr = ptr->next, count++ )
143 if ( handle == ptr->handle )
145 IsFound = TRUE;
146 pRet = ptr;
150 LeaveCriticalSection( &IconCrst );
152 return pRet;
155 /**********************************************************************
156 * CURSORICON_AddSharedIcon
158 static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HRSRC hGroupRsrc, HANDLE handle )
160 ICONCACHE *ptr = HeapAlloc( SystemHeap, 0, sizeof(ICONCACHE) );
161 if ( !ptr ) return;
163 ptr->hModule = hModule;
164 ptr->hRsrc = hRsrc;
165 ptr->handle = handle;
166 ptr->hGroupRsrc = hGroupRsrc;
167 ptr->count = 1;
169 EnterCriticalSection( &IconCrst );
170 ptr->next = IconAnchor;
171 IconAnchor = ptr;
172 LeaveCriticalSection( &IconCrst );
175 /**********************************************************************
176 * CURSORICON_DelSharedIcon
178 static INT CURSORICON_DelSharedIcon( HANDLE handle )
180 INT count = -1;
181 ICONCACHE *ptr;
183 EnterCriticalSection( &IconCrst );
185 for ( ptr = IconAnchor; ptr; ptr = ptr->next )
186 if ( ptr->handle == handle )
188 if ( ptr->count > 0 ) ptr->count--;
189 count = ptr->count;
190 break;
193 LeaveCriticalSection( &IconCrst );
195 return count;
198 /**********************************************************************
199 * CURSORICON_FreeModuleIcons
201 void CURSORICON_FreeModuleIcons( HMODULE hModule )
203 ICONCACHE **ptr = &IconAnchor;
205 if ( HIWORD( hModule ) )
206 hModule = MapHModuleLS( hModule );
207 else
208 hModule = GetExePtr( hModule );
210 EnterCriticalSection( &IconCrst );
212 while ( *ptr )
214 if ( (*ptr)->hModule == hModule )
216 ICONCACHE *freePtr = *ptr;
217 *ptr = freePtr->next;
219 GlobalFree16( freePtr->handle );
220 HeapFree( SystemHeap, 0, freePtr );
221 continue;
223 ptr = &(*ptr)->next;
226 LeaveCriticalSection( &IconCrst );
229 /**********************************************************************
230 * CURSORICON_FindBestIcon
232 * Find the icon closest to the requested size and number of colors.
234 static CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width,
235 int height, int colors )
237 int i;
238 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
239 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
240 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
242 if (dir->idCount < 1)
244 WARN_(icon)("Empty directory!\n" );
245 return NULL;
247 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
249 /* Find Best Fit */
250 iTotalDiff = 0xFFFFFFFF;
251 iColorDiff = 0xFFFFFFFF;
252 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
254 iTempXDiff = abs(width - entry->ResInfo.icon.bWidth);
255 iTempYDiff = abs(height - entry->ResInfo.icon.bHeight);
257 if(iTotalDiff > (iTempXDiff + iTempYDiff))
259 iXDiff = iTempXDiff;
260 iYDiff = iTempYDiff;
261 iTotalDiff = iXDiff + iYDiff;
265 /* Find Best Colors for Best Fit */
266 for (i = 0, entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
268 if(abs(width - entry->ResInfo.icon.bWidth) == iXDiff &&
269 abs(height - entry->ResInfo.icon.bHeight) == iYDiff)
271 iTempColorDiff = abs(colors - entry->ResInfo.icon.bColorCount);
272 if(iColorDiff > iTempColorDiff)
274 bestEntry = entry;
275 iColorDiff = iTempColorDiff;
280 return bestEntry;
284 /**********************************************************************
285 * CURSORICON_FindBestCursor
287 * Find the cursor closest to the requested size.
288 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
289 * ignored too
291 static CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir,
292 int width, int height, int color)
294 int i, maxwidth, maxheight;
295 CURSORICONDIRENTRY *entry, *bestEntry = NULL;
297 if (dir->idCount < 1)
299 WARN_(cursor)("Empty directory!\n" );
300 return NULL;
302 if (dir->idCount == 1) return &dir->idEntries[0]; /* No choice... */
304 /* Double height to account for AND and XOR masks */
306 height *= 2;
308 /* First find the largest one smaller than or equal to the requested size*/
310 maxwidth = maxheight = 0;
311 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
312 if ((entry->ResInfo.cursor.wWidth <= width) && (entry->ResInfo.cursor.wHeight <= height) &&
313 (entry->ResInfo.cursor.wWidth > maxwidth) && (entry->ResInfo.cursor.wHeight > maxheight) &&
314 (entry->wBitCount == 1))
316 bestEntry = entry;
317 maxwidth = entry->ResInfo.cursor.wWidth;
318 maxheight = entry->ResInfo.cursor.wHeight;
320 if (bestEntry) return bestEntry;
322 /* Now find the smallest one larger than the requested size */
324 maxwidth = maxheight = 255;
325 for(i = 0,entry = &dir->idEntries[0]; i < dir->idCount; i++,entry++)
326 if ((entry->ResInfo.cursor.wWidth < maxwidth) && (entry->ResInfo.cursor.wHeight < maxheight) &&
327 (entry->wBitCount == 1))
329 bestEntry = entry;
330 maxwidth = entry->ResInfo.cursor.wWidth;
331 maxheight = entry->ResInfo.cursor.wHeight;
334 return bestEntry;
337 /*********************************************************************
338 * The main purpose of this function is to create fake resource directory
339 * and fake resource entries. There are several reasons for this:
340 * - CURSORICONDIR and CURSORICONFILEDIR differ in sizes and their
341 * fields
342 * There are some "bad" cursor files which do not have
343 * bColorCount initialized but instead one must read this info
344 * directly from corresponding DIB sections
345 * Note: wResId is index to array of pointer returned in ptrs (origin is 1)
347 BOOL CURSORICON_SimulateLoadingFromResourceW( LPWSTR filename, BOOL fCursor,
348 CURSORICONDIR **res, LPBYTE **ptr)
350 LPBYTE _free;
351 CURSORICONFILEDIR *bits;
352 int entries, size, i;
354 *res = NULL;
355 *ptr = NULL;
356 if (!(bits = (CURSORICONFILEDIR *)VIRTUAL_MapFileW( filename ))) return FALSE;
358 /* FIXME: test for inimated icons
359 * hack to load the first icon from the *.ani file
361 if ( *(LPDWORD)bits==0x46464952 ) /* "RIFF" */
362 { LPBYTE pos = (LPBYTE) bits;
363 FIXME_(cursor)("Animated icons not correctly implemented! %p \n", bits);
365 for (;;)
366 { if (*(LPDWORD)pos==0x6e6f6369) /* "icon" */
367 { FIXME_(cursor)("icon entry found! %p\n", bits);
368 pos+=4;
369 if ( !*(LPWORD) pos==0x2fe) /* iconsize */
370 { goto fail;
372 bits=(CURSORICONFILEDIR*)(pos+4);
373 FIXME_(cursor)("icon size ok. offset=%p \n", bits);
374 break;
376 pos+=2;
377 if (pos>=(LPBYTE)bits+766) goto fail;
380 if (!(entries = bits->idCount)) goto fail;
381 size = sizeof(CURSORICONDIR) + sizeof(CURSORICONDIRENTRY) * (entries - 1);
382 _free = (LPBYTE) size;
384 for (i=0; i < entries; i++)
385 size += bits->idEntries[i].dwDIBSize + (fCursor ? sizeof(POINT16): 0);
387 if (!(*ptr = HeapAlloc( GetProcessHeap(), 0,
388 entries * sizeof (CURSORICONDIRENTRY*)))) goto fail;
389 if (!(*res = HeapAlloc( GetProcessHeap(), 0, size))) goto fail;
391 _free = (LPBYTE)(*res) + (int)_free;
392 memcpy((*res), bits, 6);
393 for (i=0; i<entries; i++)
395 ((LPBYTE*)(*ptr))[i] = _free;
396 if (fCursor) {
397 (*res)->idEntries[i].ResInfo.cursor.wWidth=bits->idEntries[i].bWidth;
398 (*res)->idEntries[i].ResInfo.cursor.wHeight=bits->idEntries[i].bHeight;
399 ((LPPOINT16)_free)->x=bits->idEntries[i].xHotspot;
400 ((LPPOINT16)_free)->y=bits->idEntries[i].yHotspot;
401 _free+=sizeof(POINT16);
402 } else {
403 (*res)->idEntries[i].ResInfo.icon.bWidth=bits->idEntries[i].bWidth;
404 (*res)->idEntries[i].ResInfo.icon.bHeight=bits->idEntries[i].bHeight;
405 (*res)->idEntries[i].ResInfo.icon.bColorCount = bits->idEntries[i].bColorCount;
407 (*res)->idEntries[i].wPlanes=1;
408 (*res)->idEntries[i].wBitCount = ((LPBITMAPINFOHEADER)((LPBYTE)bits +
409 bits->idEntries[i].dwDIBOffset))->biBitCount;
410 (*res)->idEntries[i].dwBytesInRes = bits->idEntries[i].dwDIBSize;
411 (*res)->idEntries[i].wResId=i+1;
413 memcpy(_free,(LPBYTE)bits +bits->idEntries[i].dwDIBOffset,
414 (*res)->idEntries[i].dwBytesInRes);
415 _free += (*res)->idEntries[i].dwBytesInRes;
417 UnmapViewOfFile( bits );
418 return TRUE;
419 fail:
420 if (*res) HeapFree( GetProcessHeap(), 0, *res );
421 if (*ptr) HeapFree( GetProcessHeap(), 0, *ptr );
422 UnmapViewOfFile( bits );
423 return FALSE;
427 /**********************************************************************
428 * CURSORICON_CreateFromResource
430 * Create a cursor or icon from in-memory resource template.
432 * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
433 * with cbSize parameter as well.
435 static HGLOBAL16 CURSORICON_CreateFromResource( HINSTANCE16 hInstance, HGLOBAL16 hObj, LPBYTE bits,
436 UINT cbSize, BOOL bIcon, DWORD dwVersion,
437 INT width, INT height, UINT loadflags )
439 int sizeAnd, sizeXor;
440 HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
441 BITMAPOBJ *bmpXor, *bmpAnd;
442 POINT16 hotspot;
443 BITMAPINFO *bmi;
444 HDC hdc;
445 BOOL DoStretch;
446 INT size;
448 hotspot.x = ICON_HOTSPOT;
449 hotspot.y = ICON_HOTSPOT;
451 TRACE_(cursor)("%08x (%u bytes), ver %08x, %ix%i %s %s\n",
452 (unsigned)bits, cbSize, (unsigned)dwVersion, width, height,
453 bIcon ? "icon" : "cursor", (loadflags & LR_MONOCHROME) ? "mono" : "" );
454 if (dwVersion == 0x00020000)
456 FIXME_(cursor)("\t2.xx resources are not supported\n");
457 return 0;
460 if (bIcon)
461 bmi = (BITMAPINFO *)bits;
462 else /* get the hotspot */
464 POINT16 *pt = (POINT16 *)bits;
465 hotspot = *pt;
466 bmi = (BITMAPINFO *)(pt + 1);
468 size = DIB_BitmapInfoSize( bmi, DIB_RGB_COLORS );
470 if (!width) width = bmi->bmiHeader.biWidth;
471 if (!height) height = bmi->bmiHeader.biHeight/2;
472 DoStretch = (bmi->bmiHeader.biHeight/2 != height) ||
473 (bmi->bmiHeader.biWidth != width);
475 /* Check bitmap header */
477 if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
478 (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) ||
479 bmi->bmiHeader.biCompression != BI_RGB) )
481 WARN_(cursor)("\tinvalid resource bitmap header.\n");
482 return 0;
485 if( (hdc = GetDC( 0 )) )
487 BITMAPINFO* pInfo;
489 /* Make sure we have room for the monochrome bitmap later on.
490 * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
491 * up to and including the biBitCount. In-memory icon resource
492 * format is as follows:
494 * BITMAPINFOHEADER icHeader // DIB header
495 * RGBQUAD icColors[] // Color table
496 * BYTE icXOR[] // DIB bits for XOR mask
497 * BYTE icAND[] // DIB bits for AND mask
500 if ((pInfo = (BITMAPINFO *)HeapAlloc( GetProcessHeap(), 0,
501 MAX(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))))
503 memcpy( pInfo, bmi, size );
504 pInfo->bmiHeader.biHeight /= 2;
506 /* Create the XOR bitmap */
508 if (DoStretch) {
509 if(bIcon)
511 hXorBits = CreateCompatibleBitmap(hdc, width, height);
513 else
515 hXorBits = CreateBitmap(width, height, 1, 1, NULL);
517 if(hXorBits)
519 HBITMAP hOld;
520 HDC hMem = CreateCompatibleDC(hdc);
521 BOOL res;
523 if (hMem) {
524 hOld = SelectObject(hMem, hXorBits);
525 res = StretchDIBits(hMem, 0, 0, width, height, 0, 0,
526 bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2,
527 (char*)bmi + size, pInfo, DIB_RGB_COLORS, SRCCOPY);
528 SelectObject(hMem, hOld);
529 DeleteDC(hMem);
530 } else res = FALSE;
531 if (!res) { DeleteObject(hXorBits); hXorBits = 0; }
533 } else hXorBits = CreateDIBitmap( hdc, &pInfo->bmiHeader,
534 CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS );
535 if( hXorBits )
537 char* bits = (char *)bmi + size +
538 DIB_GetDIBImageBytes(bmi->bmiHeader.biWidth,
539 bmi->bmiHeader.biHeight,
540 bmi->bmiHeader.biBitCount) / 2;
542 pInfo->bmiHeader.biBitCount = 1;
543 if (pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
545 RGBQUAD *rgb = pInfo->bmiColors;
547 pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
548 rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
549 rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
550 rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
552 else
554 RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
556 rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
557 rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
560 /* Create the AND bitmap */
562 if (DoStretch) {
563 if ((hAndBits = CreateBitmap(width, height, 1, 1, NULL))) {
564 HBITMAP hOld;
565 HDC hMem = CreateCompatibleDC(hdc);
566 BOOL res;
568 if (hMem) {
569 hOld = SelectObject(hMem, hAndBits);
570 res = StretchDIBits(hMem, 0, 0, width, height, 0, 0,
571 pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight,
572 bits, pInfo, DIB_RGB_COLORS, SRCCOPY);
573 SelectObject(hMem, hOld);
574 DeleteDC(hMem);
575 } else res = FALSE;
576 if (!res) { DeleteObject(hAndBits); hAndBits = 0; }
578 } else hAndBits = CreateDIBitmap( hdc, &pInfo->bmiHeader,
579 CBM_INIT, bits, pInfo, DIB_RGB_COLORS );
581 if( !hAndBits ) DeleteObject( hXorBits );
583 HeapFree( GetProcessHeap(), 0, pInfo );
585 ReleaseDC( 0, hdc );
588 if( !hXorBits || !hAndBits )
590 WARN_(cursor)("\tunable to create an icon bitmap.\n");
591 return 0;
594 /* Now create the CURSORICONINFO structure */
595 bmpXor = (BITMAPOBJ *) GDI_GetObjPtr( hXorBits, BITMAP_MAGIC );
596 bmpAnd = (BITMAPOBJ *) GDI_GetObjPtr( hAndBits, BITMAP_MAGIC );
597 sizeXor = bmpXor->bitmap.bmHeight * bmpXor->bitmap.bmWidthBytes;
598 sizeAnd = bmpAnd->bitmap.bmHeight * bmpAnd->bitmap.bmWidthBytes;
600 if (hObj) hObj = GlobalReAlloc16( hObj,
601 sizeof(CURSORICONINFO) + sizeXor + sizeAnd, GMEM_MOVEABLE );
602 if (!hObj) hObj = GlobalAlloc16( GMEM_MOVEABLE,
603 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
604 if (hObj)
606 CURSORICONINFO *info;
608 /* Make it owned by the module */
609 if (hInstance) FarSetOwner16( hObj, GetExePtr(hInstance) );
611 info = (CURSORICONINFO *)GlobalLock16( hObj );
612 info->ptHotSpot.x = hotspot.x;
613 info->ptHotSpot.y = hotspot.y;
614 info->nWidth = bmpXor->bitmap.bmWidth;
615 info->nHeight = bmpXor->bitmap.bmHeight;
616 info->nWidthBytes = bmpXor->bitmap.bmWidthBytes;
617 info->bPlanes = bmpXor->bitmap.bmPlanes;
618 info->bBitsPerPixel = bmpXor->bitmap.bmBitsPixel;
620 /* Transfer the bitmap bits to the CURSORICONINFO structure */
622 GetBitmapBits( hAndBits, sizeAnd, (char *)(info + 1) );
623 GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
624 GlobalUnlock16( hObj );
627 DeleteObject( hXorBits );
628 DeleteObject( hAndBits );
629 return hObj;
633 /**********************************************************************
634 * CreateIconFromResourceEx16 (USER.450)
636 * FIXME: not sure about exact parameter types
638 HICON16 WINAPI CreateIconFromResourceEx16( LPBYTE bits, UINT16 cbSize, BOOL16 bIcon,
639 DWORD dwVersion, INT16 width, INT16 height, UINT16 cFlag )
641 return CreateIconFromResourceEx(bits, cbSize, bIcon, dwVersion,
642 width, height, cFlag);
646 /**********************************************************************
647 * CreateIconFromResource (USER32.76)
649 HICON WINAPI CreateIconFromResource( LPBYTE bits, UINT cbSize,
650 BOOL bIcon, DWORD dwVersion)
652 return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
656 /**********************************************************************
657 * CreateIconFromResourceEx32 (USER32.77)
659 HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
660 BOOL bIcon, DWORD dwVersion,
661 INT width, INT height,
662 UINT cFlag )
664 TDB* pTask = (TDB*)GlobalLock16( GetCurrentTask() );
665 if( pTask )
666 return CURSORICON_CreateFromResource( pTask->hInstance, 0, bits, cbSize, bIcon, dwVersion,
667 width, height, cFlag );
668 return 0;
671 /**********************************************************************
672 * CURSORICON_Load
674 * Load a cursor or icon from resource or file.
676 HGLOBAL CURSORICON_Load( HINSTANCE hInstance, LPCWSTR name,
677 INT width, INT height, INT colors,
678 BOOL fCursor, UINT loadflags )
680 HANDLE handle = 0, h = 0;
681 HANDLE hRsrc;
682 CURSORICONDIR *dir;
683 CURSORICONDIRENTRY *dirEntry;
684 LPBYTE bits;
686 if ( loadflags & LR_LOADFROMFILE ) /* Load from file */
688 LPBYTE *ptr;
689 if (!CURSORICON_SimulateLoadingFromResourceW((LPWSTR)name, fCursor, &dir, &ptr))
690 return 0;
691 if (fCursor)
692 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(dir, width, height, 1);
693 else
694 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(dir, width, height, colors);
695 bits = ptr[dirEntry->wResId-1];
696 h = CURSORICON_CreateFromResource( 0, 0, bits, dirEntry->dwBytesInRes,
697 !fCursor, 0x00030000, width, height, loadflags);
698 HeapFree( GetProcessHeap(), 0, dir );
699 HeapFree( GetProcessHeap(), 0, ptr );
702 else if ( !hInstance ) /* Load OEM cursor/icon */
704 WORD resid;
705 HDC hdc;
707 if ( HIWORD(name) )
709 LPSTR ansi = HEAP_strdupWtoA(GetProcessHeap(),0,name);
710 if( ansi[0]=='#') /*Check for '#xxx' name */
712 resid = atoi(ansi+1);
713 HeapFree( GetProcessHeap(), 0, ansi );
715 else
717 HeapFree( GetProcessHeap(), 0, ansi );
718 return 0;
721 else resid = LOWORD(name);
722 hdc = CreateDCA( "DISPLAY", NULL, NULL, NULL );
723 if (hdc) {
724 DC *dc = DC_GetDCPtr( hdc );
725 if (dc->funcs->pLoadOEMResource)
726 h = dc->funcs->pLoadOEMResource( resid, fCursor ? OEM_CURSOR : OEM_ICON );
727 GDI_HEAP_UNLOCK( hdc );
728 DeleteDC( hdc );
732 else /* Load from resource */
734 HANDLE hGroupRsrc;
735 WORD wResId;
736 DWORD dwBytesInRes;
738 /* Normalize hInstance (must be uniquely represented for icon cache) */
740 if ( HIWORD( hInstance ) )
741 hInstance = MapHModuleLS( hInstance );
742 else
743 hInstance = GetExePtr( hInstance );
745 /* Get directory resource ID */
747 if (!(hRsrc = FindResourceW( hInstance, name,
748 fCursor ? RT_GROUP_CURSORW : RT_GROUP_ICONW )))
749 return 0;
750 hGroupRsrc = hRsrc;
751 /* If shared icon, check whether it was already loaded */
753 if ( (loadflags & LR_SHARED)
754 && (h = CURSORICON_FindSharedIcon( hInstance, hRsrc ) ) != 0 )
755 return h;
757 /* Find the best entry in the directory */
759 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
760 if (!(dir = (CURSORICONDIR*)LockResource( handle ))) return 0;
761 if (fCursor)
762 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor( dir,
763 width, height, 1);
764 else
765 dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon( dir,
766 width, height, colors );
767 if (!dirEntry) return 0;
768 wResId = dirEntry->wResId;
769 dwBytesInRes = dirEntry->dwBytesInRes;
770 FreeResource( handle );
772 /* Load the resource */
774 if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
775 fCursor ? RT_CURSORW : RT_ICONW ))) return 0;
776 if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
777 bits = (LPBYTE)LockResource( handle );
778 h = CURSORICON_CreateFromResource( 0, 0, bits, dwBytesInRes,
779 !fCursor, 0x00030000, width, height, loadflags);
780 FreeResource( handle );
782 /* If shared icon, add to icon cache */
784 if ( h && (loadflags & LR_SHARED) )
785 CURSORICON_AddSharedIcon( hInstance, hRsrc, hGroupRsrc, h );
788 return h;
791 /***********************************************************************
792 * CURSORICON_Copy
794 * Make a copy of a cursor or icon.
796 static HGLOBAL16 CURSORICON_Copy( HINSTANCE16 hInstance, HGLOBAL16 handle )
798 char *ptrOld, *ptrNew;
799 int size;
800 HGLOBAL16 hNew;
802 if (!(ptrOld = (char *)GlobalLock16( handle ))) return 0;
803 if (!(hInstance = GetExePtr( hInstance ))) return 0;
804 size = GlobalSize16( handle );
805 hNew = GlobalAlloc16( GMEM_MOVEABLE, size );
806 FarSetOwner16( hNew, hInstance );
807 ptrNew = (char *)GlobalLock16( hNew );
808 memcpy( ptrNew, ptrOld, size );
809 GlobalUnlock16( handle );
810 GlobalUnlock16( hNew );
811 return hNew;
814 /*************************************************************************
815 * CURSORICON_ExtCopy
817 * Copies an Image from the Cache if LR_COPYFROMRESOURCE is specified
819 * PARAMS
820 * Handle [I] handle to an Image
821 * nType [I] Type of Handle (IMAGE_CURSOR | IMAGE_ICON)
822 * iDesiredCX [I] The Desired width of the Image
823 * iDesiredCY [I] The desired height of the Image
824 * nFlags [I] The flags from CopyImage
826 * RETURNS
827 * Success: The new handle of the Image
829 * NOTES
830 * LR_COPYDELETEORG and LR_MONOCHROME are currently not implemented.
831 * LR_MONOCHROME should be implemented by CURSORICON_CreateFromResource.
832 * LR_COPYFROMRESOURCE will only work if the Image is in the Cache.
837 HGLOBAL CURSORICON_ExtCopy(HGLOBAL Handle, UINT nType,
838 INT iDesiredCX, INT iDesiredCY,
839 UINT nFlags)
841 HGLOBAL16 hNew=0;
843 TRACE_(icon)("Handle %u, uType %u, iDesiredCX %i, iDesiredCY %i, nFlags %u\n",
844 Handle, nType, iDesiredCX, iDesiredCY, nFlags);
846 if(Handle == 0)
848 return 0;
851 /* Best Fit or Monochrome */
852 if( (nFlags & LR_COPYFROMRESOURCE
853 && (iDesiredCX > 0 || iDesiredCY > 0))
854 || nFlags & LR_MONOCHROME)
856 ICONCACHE* pIconCache = CURSORICON_FindCache(Handle);
858 /* Not Found in Cache, then do a strait copy
860 if(pIconCache == NULL)
862 TDB* pTask = (TDB *) GlobalLock16 (GetCurrentTask ());
863 hNew = CURSORICON_Copy(pTask->hInstance, Handle);
864 if(nFlags & LR_COPYFROMRESOURCE)
866 TRACE_(icon)("LR_COPYFROMRESOURCE: Failed to load from cache\n");
869 else
871 int iTargetCY = iDesiredCY, iTargetCX = iDesiredCX;
872 LPBYTE pBits;
873 HANDLE hMem;
874 HRSRC hRsrc;
875 DWORD dwBytesInRes;
876 WORD wResId;
877 CURSORICONDIR *pDir;
878 CURSORICONDIRENTRY *pDirEntry;
879 BOOL bIsIcon = (nType == IMAGE_ICON);
881 /* Completing iDesiredCX CY for Monochrome Bitmaps if needed
883 if(((nFlags & LR_MONOCHROME) && !(nFlags & LR_COPYFROMRESOURCE))
884 || (iDesiredCX == 0 && iDesiredCY == 0))
886 iDesiredCY = GetSystemMetrics(bIsIcon ?
887 SM_CYICON : SM_CYCURSOR);
888 iDesiredCX = GetSystemMetrics(bIsIcon ?
889 SM_CXICON : SM_CXCURSOR);
892 /* Retreive the CURSORICONDIRENTRY
894 if (!(hMem = LoadResource( pIconCache->hModule ,
895 pIconCache->hGroupRsrc)))
897 return 0;
899 if (!(pDir = (CURSORICONDIR*)LockResource( hMem )))
901 return 0;
904 /* Find Best Fit
906 if(bIsIcon)
908 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(
909 pDir, iDesiredCX, iDesiredCY, 256);
911 else
913 pDirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestCursor(
914 pDir, iDesiredCX, iDesiredCY, 1);
917 wResId = pDirEntry->wResId;
918 dwBytesInRes = pDirEntry->dwBytesInRes;
919 FreeResource(hMem);
921 TRACE_(icon)("ResID %u, BytesInRes %lu, Width %d, Height %d DX %d, DY %d\n",
922 wResId, dwBytesInRes, pDirEntry->ResInfo.icon.bWidth,
923 pDirEntry->ResInfo.icon.bHeight, iDesiredCX, iDesiredCY);
925 /* Get the Best Fit
927 if (!(hRsrc = FindResourceW(pIconCache->hModule ,
928 MAKEINTRESOURCEW(wResId), bIsIcon ? RT_ICONW : RT_CURSORW)))
930 return 0;
932 if (!(hMem = LoadResource( pIconCache->hModule , hRsrc )))
934 return 0;
937 pBits = (LPBYTE)LockResource( hMem );
939 if(nFlags & LR_DEFAULTSIZE)
941 iTargetCY = GetSystemMetrics(SM_CYICON);
942 iTargetCX = GetSystemMetrics(SM_CXICON);
945 /* Create a New Icon with the proper dimension
947 hNew = CURSORICON_CreateFromResource( 0, 0, pBits, dwBytesInRes,
948 bIsIcon, 0x00030000, iTargetCX, iTargetCY, nFlags);
949 FreeResource(hMem);
952 else
954 TDB* pTask = (TDB *) GlobalLock16 (GetCurrentTask ());
955 hNew = CURSORICON_Copy(pTask->hInstance, Handle);
957 return hNew;
960 /***********************************************************************
961 * CURSORICON_IconToCursor
963 * Converts bitmap to mono and truncates if icon is too large (should
964 * probably do StretchBlt() instead).
966 HCURSOR16 CURSORICON_IconToCursor(HICON16 hIcon, BOOL bSemiTransparent)
968 HCURSOR16 hRet = 0;
969 CURSORICONINFO *pIcon = NULL;
970 HTASK16 hTask = GetCurrentTask();
971 TDB* pTask = (TDB *)GlobalLock16(hTask);
973 if(hIcon && pTask)
974 if (!(pIcon = (CURSORICONINFO*)GlobalLock16( hIcon ))) return FALSE;
975 if (pIcon->bPlanes * pIcon->bBitsPerPixel == 1)
977 hRet = CURSORICON_Copy( pTask->hInstance, hIcon );
980 pIcon = GlobalLock16(hRet);
982 pIcon->ptHotSpot.x = pIcon->ptHotSpot.y = 15;
984 GlobalUnlock16(hRet);
986 else
988 BYTE pAndBits[128];
989 BYTE pXorBits[128];
990 int maxx, maxy, ix, iy, bpp = pIcon->bBitsPerPixel;
991 BYTE* psPtr, *pxbPtr = pXorBits;
992 unsigned xor_width, and_width, val_base = 0xffffffff >> (32 - bpp);
993 BYTE* pbc = NULL;
995 CURSORICONINFO cI;
997 TRACE_(icon)("[%04x] %ix%i %ibpp (bogus %ibps)\n",
998 hIcon, pIcon->nWidth, pIcon->nHeight, pIcon->bBitsPerPixel, pIcon->nWidthBytes );
1000 xor_width = BITMAP_GetWidthBytes( pIcon->nWidth, bpp );
1001 and_width = BITMAP_GetWidthBytes( pIcon->nWidth, 1 );
1002 psPtr = (BYTE *)(pIcon + 1) + pIcon->nHeight * and_width;
1004 memset(pXorBits, 0, 128);
1005 cI.bBitsPerPixel = 1; cI.bPlanes = 1;
1006 cI.ptHotSpot.x = cI.ptHotSpot.y = 15;
1007 cI.nWidth = 32; cI.nHeight = 32;
1008 cI.nWidthBytes = 4; /* 32x1bpp */
1010 maxx = (pIcon->nWidth > 32) ? 32 : pIcon->nWidth;
1011 maxy = (pIcon->nHeight > 32) ? 32 : pIcon->nHeight;
1013 for( iy = 0; iy < maxy; iy++ )
1015 unsigned shift = iy % 2;
1017 memcpy( pAndBits + iy * 4, (BYTE *)(pIcon + 1) + iy * and_width,
1018 (and_width > 4) ? 4 : and_width );
1019 for( ix = 0; ix < maxx; ix++ )
1021 if( bSemiTransparent && ((ix+shift)%2) )
1023 /* set AND bit, XOR bit stays 0 */
1025 pbc = pAndBits + iy * 4 + ix/8;
1026 *pbc |= 0x80 >> (ix%8);
1028 else
1030 /* keep AND bit, set XOR bit */
1032 unsigned *psc = (unsigned*)(psPtr + (ix * bpp)/8);
1033 unsigned val = ((*psc) >> (ix * bpp)%8) & val_base;
1034 if(!PALETTE_Driver->pIsDark(val))
1036 pbc = pxbPtr + ix/8;
1037 *pbc |= 0x80 >> (ix%8);
1041 psPtr += xor_width;
1042 pxbPtr += 4;
1045 hRet = CreateCursorIconIndirect16( pTask->hInstance , &cI, pAndBits, pXorBits);
1047 if( !hRet ) /* fall back on default drag cursor */
1048 hRet = CURSORICON_Copy( pTask->hInstance ,
1049 CURSORICON_Load(0,MAKEINTRESOURCEW(OCR_DRAGOBJECT),
1050 GetSystemMetrics(SM_CXCURSOR),
1051 GetSystemMetrics(SM_CYCURSOR), 1, TRUE, 0) );
1054 return hRet;
1058 /***********************************************************************
1059 * LoadCursor16 (USER.173)
1061 HCURSOR16 WINAPI LoadCursor16( HINSTANCE16 hInstance, SEGPTR name )
1063 LPCSTR nameStr = HIWORD(name)? PTR_SEG_TO_LIN(name) : (LPCSTR)name;
1064 return LoadCursorA( hInstance, nameStr );
1068 /***********************************************************************
1069 * LoadIcon16 (USER.174)
1071 HICON16 WINAPI LoadIcon16( HINSTANCE16 hInstance, SEGPTR name )
1073 LPCSTR nameStr = HIWORD(name)? PTR_SEG_TO_LIN(name) : (LPCSTR)name;
1074 return LoadIconA( hInstance, nameStr );
1078 /***********************************************************************
1079 * CreateCursor16 (USER.406)
1081 HCURSOR16 WINAPI CreateCursor16( HINSTANCE16 hInstance,
1082 INT16 xHotSpot, INT16 yHotSpot,
1083 INT16 nWidth, INT16 nHeight,
1084 LPCVOID lpANDbits, LPCVOID lpXORbits )
1086 CURSORICONINFO info;
1088 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1089 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1091 info.ptHotSpot.x = xHotSpot;
1092 info.ptHotSpot.y = yHotSpot;
1093 info.nWidth = nWidth;
1094 info.nHeight = nHeight;
1095 info.nWidthBytes = 0;
1096 info.bPlanes = 1;
1097 info.bBitsPerPixel = 1;
1099 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1103 /***********************************************************************
1104 * CreateCursor32 (USER32.67)
1106 HCURSOR WINAPI CreateCursor( HINSTANCE hInstance,
1107 INT xHotSpot, INT yHotSpot,
1108 INT nWidth, INT nHeight,
1109 LPCVOID lpANDbits, LPCVOID lpXORbits )
1111 CURSORICONINFO info;
1113 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1114 nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1116 info.ptHotSpot.x = xHotSpot;
1117 info.ptHotSpot.y = yHotSpot;
1118 info.nWidth = nWidth;
1119 info.nHeight = nHeight;
1120 info.nWidthBytes = 0;
1121 info.bPlanes = 1;
1122 info.bBitsPerPixel = 1;
1124 return CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
1128 /***********************************************************************
1129 * CreateIcon16 (USER.407)
1131 HICON16 WINAPI CreateIcon16( HINSTANCE16 hInstance, INT16 nWidth,
1132 INT16 nHeight, BYTE bPlanes, BYTE bBitsPixel,
1133 LPCVOID lpANDbits, LPCVOID lpXORbits )
1135 CURSORICONINFO info;
1137 TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1138 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1140 info.ptHotSpot.x = ICON_HOTSPOT;
1141 info.ptHotSpot.y = ICON_HOTSPOT;
1142 info.nWidth = nWidth;
1143 info.nHeight = nHeight;
1144 info.nWidthBytes = 0;
1145 info.bPlanes = bPlanes;
1146 info.bBitsPerPixel = bBitsPixel;
1148 return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
1152 /***********************************************************************
1153 * CreateIcon32 (USER32.75)
1155 HICON WINAPI CreateIcon( HINSTANCE hInstance, INT nWidth,
1156 INT nHeight, BYTE bPlanes, BYTE bBitsPixel,
1157 LPCVOID lpANDbits, LPCVOID lpXORbits )
1159 CURSORICONINFO info;
1161 TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
1162 nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1164 info.ptHotSpot.x = ICON_HOTSPOT;
1165 info.ptHotSpot.y = ICON_HOTSPOT;
1166 info.nWidth = nWidth;
1167 info.nHeight = nHeight;
1168 info.nWidthBytes = 0;
1169 info.bPlanes = bPlanes;
1170 info.bBitsPerPixel = bBitsPixel;
1172 return CreateCursorIconIndirect16( 0, &info, lpANDbits, lpXORbits );
1176 /***********************************************************************
1177 * CreateCursorIconIndirect (USER.408)
1179 HGLOBAL16 WINAPI CreateCursorIconIndirect16( HINSTANCE16 hInstance,
1180 CURSORICONINFO *info,
1181 LPCVOID lpANDbits,
1182 LPCVOID lpXORbits )
1184 HGLOBAL16 handle;
1185 char *ptr;
1186 int sizeAnd, sizeXor;
1188 hInstance = GetExePtr( hInstance ); /* Make it a module handle */
1189 if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
1190 info->nWidthBytes = BITMAP_GetWidthBytes(info->nWidth,info->bBitsPerPixel);
1191 sizeXor = info->nHeight * info->nWidthBytes;
1192 sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
1193 if (!(handle = GlobalAlloc16( GMEM_MOVEABLE,
1194 sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
1195 return 0;
1196 if (hInstance) FarSetOwner16( handle, hInstance );
1197 ptr = (char *)GlobalLock16( handle );
1198 memcpy( ptr, info, sizeof(*info) );
1199 memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
1200 memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
1201 GlobalUnlock16( handle );
1202 return handle;
1206 /***********************************************************************
1207 * CopyIcon16 (USER.368)
1209 HICON16 WINAPI CopyIcon16( HINSTANCE16 hInstance, HICON16 hIcon )
1211 TRACE_(icon)("%04x %04x\n", hInstance, hIcon );
1212 return CURSORICON_Copy( hInstance, hIcon );
1216 /***********************************************************************
1217 * CopyIcon32 (USER32.60)
1219 HICON WINAPI CopyIcon( HICON hIcon )
1221 HTASK16 hTask = GetCurrentTask ();
1222 TDB* pTask = (TDB *) GlobalLock16 (hTask);
1223 TRACE_(icon)("%04x\n", hIcon );
1224 return CURSORICON_Copy( pTask->hInstance, hIcon );
1228 /***********************************************************************
1229 * CopyCursor16 (USER.369)
1231 HCURSOR16 WINAPI CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
1233 TRACE_(cursor)("%04x %04x\n", hInstance, hCursor );
1234 return CURSORICON_Copy( hInstance, hCursor );
1237 /**********************************************************************
1238 * CURSORICON_Destroy (USER.610)
1240 * This routine is actually exported from Win95 USER under the name
1241 * DestroyIcon32 ... The behaviour implemented here should mimic
1242 * the Win95 one exactly, especially the return values, which
1243 * depend on the setting of various flags.
1245 WORD WINAPI CURSORICON_Destroy( HGLOBAL16 handle, UINT16 flags )
1247 WORD retv;
1249 TRACE_(icon)("(%04x, %04x)\n", handle, flags );
1251 /* Check whether destroying active cursor */
1253 if ( hActiveCursor == handle )
1255 ERR_(cursor)("Destroying active cursor!\n" );
1256 SetCursor( 0 );
1259 /* Try shared cursor/icon first */
1261 if ( !(flags & CID_NONSHARED) )
1263 INT count = CURSORICON_DelSharedIcon( handle );
1265 if ( count != -1 )
1266 return (flags & CID_WIN32)? TRUE : (count == 0);
1268 /* FIXME: OEM cursors/icons should be recognized */
1271 /* Now assume non-shared cursor/icon */
1273 retv = GlobalFree16( handle );
1274 return (flags & CID_RESOURCE)? retv : TRUE;
1277 /***********************************************************************
1278 * DestroyIcon16 (USER.457)
1280 BOOL16 WINAPI DestroyIcon16( HICON16 hIcon )
1282 return CURSORICON_Destroy( hIcon, 0 );
1285 /***********************************************************************
1286 * DestroyIcon (USER32.133)
1288 BOOL WINAPI DestroyIcon( HICON hIcon )
1290 return CURSORICON_Destroy( hIcon, CID_WIN32 );
1293 /***********************************************************************
1294 * DestroyCursor16 (USER.458)
1296 BOOL16 WINAPI DestroyCursor16( HCURSOR16 hCursor )
1298 return CURSORICON_Destroy( hCursor, 0 );
1301 /***********************************************************************
1302 * DestroyCursor (USER32.132)
1304 BOOL WINAPI DestroyCursor( HCURSOR hCursor )
1306 return CURSORICON_Destroy( hCursor, CID_WIN32 );
1310 /***********************************************************************
1311 * DrawIcon16 (USER.84)
1313 BOOL16 WINAPI DrawIcon16( HDC16 hdc, INT16 x, INT16 y, HICON16 hIcon )
1315 return DrawIcon( hdc, x, y, hIcon );
1319 /***********************************************************************
1320 * DrawIcon32 (USER32.159)
1322 BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
1324 CURSORICONINFO *ptr;
1325 HDC hMemDC;
1326 HBITMAP hXorBits, hAndBits;
1327 COLORREF oldFg, oldBg;
1329 if (!(ptr = (CURSORICONINFO *)GlobalLock16( hIcon ))) return FALSE;
1330 if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
1331 hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1,
1332 (char *)(ptr+1) );
1333 hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
1334 ptr->bBitsPerPixel, (char *)(ptr + 1)
1335 + ptr->nHeight * BITMAP_GetWidthBytes(ptr->nWidth,1) );
1336 oldFg = SetTextColor( hdc, RGB(0,0,0) );
1337 oldBg = SetBkColor( hdc, RGB(255,255,255) );
1339 if (hXorBits && hAndBits)
1341 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1342 BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
1343 SelectObject( hMemDC, hXorBits );
1344 BitBlt(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
1345 SelectObject( hMemDC, hBitTemp );
1347 DeleteDC( hMemDC );
1348 if (hXorBits) DeleteObject( hXorBits );
1349 if (hAndBits) DeleteObject( hAndBits );
1350 GlobalUnlock16( hIcon );
1351 SetTextColor( hdc, oldFg );
1352 SetBkColor( hdc, oldBg );
1353 return TRUE;
1357 /***********************************************************************
1358 * DumpIcon (USER.459)
1360 DWORD WINAPI DumpIcon16( SEGPTR pInfo, WORD *lpLen,
1361 SEGPTR *lpXorBits, SEGPTR *lpAndBits )
1363 CURSORICONINFO *info = PTR_SEG_TO_LIN( pInfo );
1364 int sizeAnd, sizeXor;
1366 if (!info) return 0;
1367 sizeXor = info->nHeight * info->nWidthBytes;
1368 sizeAnd = info->nHeight * BITMAP_GetWidthBytes( info->nWidth, 1 );
1369 if (lpAndBits) *lpAndBits = pInfo + sizeof(CURSORICONINFO);
1370 if (lpXorBits) *lpXorBits = pInfo + sizeof(CURSORICONINFO) + sizeAnd;
1371 if (lpLen) *lpLen = sizeof(CURSORICONINFO) + sizeAnd + sizeXor;
1372 return MAKELONG( sizeXor, sizeXor );
1376 /***********************************************************************
1377 * SetCursor16 (USER.69)
1379 HCURSOR16 WINAPI SetCursor16( HCURSOR16 hCursor )
1381 return (HCURSOR16)SetCursor( hCursor );
1385 /***********************************************************************
1386 * SetCursor32 (USER32.472)
1387 * RETURNS:
1388 * A handle to the previous cursor shape.
1390 HCURSOR WINAPI SetCursor(
1391 HCURSOR hCursor /* Handle of cursor to show */
1393 HCURSOR hOldCursor;
1395 if (hCursor == hActiveCursor) return hActiveCursor; /* No change */
1396 TRACE_(cursor)("%04x\n", hCursor );
1397 hOldCursor = hActiveCursor;
1398 hActiveCursor = hCursor;
1399 /* Change the cursor shape only if it is visible */
1400 if (CURSOR_ShowCount >= 0)
1402 DISPLAY_SetCursor( (CURSORICONINFO*)GlobalLock16( hActiveCursor ) );
1403 GlobalUnlock16( hActiveCursor );
1405 return hOldCursor;
1409 /***********************************************************************
1410 * SetCursorPos16 (USER.70)
1412 void WINAPI SetCursorPos16( INT16 x, INT16 y )
1414 SetCursorPos( x, y );
1418 /***********************************************************************
1419 * SetCursorPos32 (USER32.474)
1421 BOOL WINAPI SetCursorPos( INT x, INT y )
1423 DISPLAY_MoveCursor( x, y );
1424 return TRUE;
1428 /***********************************************************************
1429 * ShowCursor16 (USER.71)
1431 INT16 WINAPI ShowCursor16( BOOL16 bShow )
1433 return ShowCursor( bShow );
1437 /***********************************************************************
1438 * ShowCursor32 (USER32.530)
1440 INT WINAPI ShowCursor( BOOL bShow )
1442 TRACE_(cursor)("%d, count=%d\n",
1443 bShow, CURSOR_ShowCount );
1445 if (bShow)
1447 if (++CURSOR_ShowCount == 0) /* Show it */
1449 DISPLAY_SetCursor((CURSORICONINFO*)GlobalLock16( hActiveCursor ));
1450 GlobalUnlock16( hActiveCursor );
1453 else
1455 if (--CURSOR_ShowCount == -1) /* Hide it */
1456 DISPLAY_SetCursor( NULL );
1458 return CURSOR_ShowCount;
1462 /***********************************************************************
1463 * GetCursor16 (USER.247)
1465 HCURSOR16 WINAPI GetCursor16(void)
1467 return hActiveCursor;
1471 /***********************************************************************
1472 * GetCursor32 (USER32.227)
1474 HCURSOR WINAPI GetCursor(void)
1476 return hActiveCursor;
1480 /***********************************************************************
1481 * ClipCursor16 (USER.16)
1483 BOOL16 WINAPI ClipCursor16( const RECT16 *rect )
1485 if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1486 else CONV_RECT16TO32( rect, &CURSOR_ClipRect );
1487 return TRUE;
1491 /***********************************************************************
1492 * ClipCursor32 (USER32.53)
1494 BOOL WINAPI ClipCursor( const RECT *rect )
1496 if (!rect) SetRectEmpty( &CURSOR_ClipRect );
1497 else CopyRect( &CURSOR_ClipRect, rect );
1498 return TRUE;
1502 /***********************************************************************
1503 * GetCursorPos16 (USER.17)
1505 BOOL16 WINAPI GetCursorPos16( POINT16 *pt )
1507 if (!pt) return 0;
1509 pt->x = PosX;
1510 pt->y = PosY;
1512 TRACE_(cursor)("ret=%d,%d\n", pt->x, pt->y );
1513 return 1;
1517 /***********************************************************************
1518 * GetCursorPos32 (USER32.229)
1520 BOOL WINAPI GetCursorPos( POINT *pt )
1522 BOOL ret;
1524 POINT16 pt16;
1525 ret = GetCursorPos16( &pt16 );
1526 if (pt) CONV_POINT16TO32( &pt16, pt );
1527 return ((pt) ? ret : 0);
1531 /***********************************************************************
1532 * GetClipCursor16 (USER.309)
1534 void WINAPI GetClipCursor16( RECT16 *rect )
1536 if (rect) CONV_RECT32TO16( &CURSOR_ClipRect, rect );
1540 /***********************************************************************
1541 * GetClipCursor32 (USER32.221)
1543 BOOL WINAPI GetClipCursor( RECT *rect )
1545 if (rect)
1547 CopyRect( rect, &CURSOR_ClipRect );
1548 return TRUE;
1550 return FALSE;
1553 /**********************************************************************
1554 * LookupIconIdFromDirectoryEx16 (USER.364)
1556 * FIXME: exact parameter sizes
1558 INT16 WINAPI LookupIconIdFromDirectoryEx16( LPBYTE xdir, BOOL16 bIcon,
1559 INT16 width, INT16 height, UINT16 cFlag )
1561 CURSORICONDIR *dir = (CURSORICONDIR*)xdir;
1562 UINT16 retVal = 0;
1563 if( dir && !dir->idReserved && (dir->idType & 3) )
1565 CURSORICONDIRENTRY* entry;
1566 HDC hdc;
1567 UINT palEnts;
1568 int colors;
1569 hdc = GetDC(0);
1570 palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
1571 if (palEnts == 0)
1572 palEnts = 256;
1573 colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;
1575 ReleaseDC(0, hdc);
1577 if( bIcon )
1578 entry = CURSORICON_FindBestIcon( dir, width, height, colors );
1579 else
1580 entry = CURSORICON_FindBestCursor( dir, width, height, 1);
1582 if( entry ) retVal = entry->wResId;
1584 else WARN_(cursor)("invalid resource directory\n");
1585 return retVal;
1588 /**********************************************************************
1589 * LookupIconIdFromDirectoryEx32 (USER32.380)
1591 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE dir, BOOL bIcon,
1592 INT width, INT height, UINT cFlag )
1594 return LookupIconIdFromDirectoryEx16( dir, bIcon, width, height, cFlag );
1597 /**********************************************************************
1598 * LookupIconIdFromDirectory (USER.???)
1600 INT16 WINAPI LookupIconIdFromDirectory16( LPBYTE dir, BOOL16 bIcon )
1602 return LookupIconIdFromDirectoryEx16( dir, bIcon,
1603 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1604 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1607 /**********************************************************************
1608 * LookupIconIdFromDirectory (USER32.379)
1610 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1612 return LookupIconIdFromDirectoryEx( dir, bIcon,
1613 bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1614 bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1617 /**********************************************************************
1618 * GetIconID (USER.455)
1620 WORD WINAPI GetIconID16( HGLOBAL16 hResource, DWORD resType )
1622 LPBYTE lpDir = (LPBYTE)GlobalLock16(hResource);
1624 TRACE_(cursor)("hRes=%04x, entries=%i\n",
1625 hResource, lpDir ? ((CURSORICONDIR*)lpDir)->idCount : 0);
1627 switch(resType)
1629 case RT_CURSOR16:
1630 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, FALSE,
1631 GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1632 case RT_ICON16:
1633 return (WORD)LookupIconIdFromDirectoryEx16( lpDir, TRUE,
1634 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0 );
1635 default:
1636 WARN_(cursor)("invalid res type %ld\n", resType );
1638 return 0;
1641 /**********************************************************************
1642 * LoadCursorIconHandler (USER.336)
1644 * Supposed to load resources of Windows 2.x applications.
1646 HGLOBAL16 WINAPI LoadCursorIconHandler16( HGLOBAL16 hResource, HMODULE16 hModule, HRSRC16 hRsrc )
1648 FIXME_(cursor)("(%04x,%04x,%04x): old 2.x resources are not supported!\n",
1649 hResource, hModule, hRsrc);
1650 return (HGLOBAL16)0;
1653 /**********************************************************************
1654 * LoadDIBIconHandler (USER.357)
1656 * RT_ICON resource loader, installed by USER_SignalProc when module
1657 * is initialized.
1659 HGLOBAL16 WINAPI LoadDIBIconHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1661 /* If hResource is zero we must allocate a new memory block, if it's
1662 * non-zero but GlobalLock() returns NULL then it was discarded and
1663 * we have to recommit some memory, otherwise we just need to check
1664 * the block size. See LoadProc() in 16-bit SDK for more.
1667 hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1668 if( hMemObj )
1670 LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1671 hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1672 SizeofResource16(hModule, hRsrc), TRUE, 0x00030000,
1673 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR );
1675 return hMemObj;
1678 /**********************************************************************
1679 * LoadDIBCursorHandler (USER.356)
1681 * RT_CURSOR resource loader. Same as above.
1683 HGLOBAL16 WINAPI LoadDIBCursorHandler16( HGLOBAL16 hMemObj, HMODULE16 hModule, HRSRC16 hRsrc )
1685 hMemObj = NE_DefResourceHandler( hMemObj, hModule, hRsrc );
1686 if( hMemObj )
1688 LPBYTE bits = (LPBYTE)GlobalLock16( hMemObj );
1689 hMemObj = CURSORICON_CreateFromResource( hModule, hMemObj, bits,
1690 SizeofResource16(hModule, hRsrc), FALSE, 0x00030000,
1691 GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
1693 return hMemObj;
1696 /**********************************************************************
1697 * LoadIconHandler (USER.456)
1699 HICON16 WINAPI LoadIconHandler16( HGLOBAL16 hResource, BOOL16 bNew )
1701 LPBYTE bits = (LPBYTE)LockResource16( hResource );
1703 TRACE_(cursor)("hRes=%04x\n",hResource);
1705 return CURSORICON_CreateFromResource( 0, 0, bits, 0, TRUE,
1706 bNew ? 0x00030000 : 0x00020000, 0, 0, LR_DEFAULTCOLOR );
1709 /***********************************************************************
1710 * LoadCursorW (USER32.362)
1712 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
1714 return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0,
1715 LR_SHARED | LR_DEFAULTSIZE );
1718 /***********************************************************************
1719 * LoadCursorA (USER32.359)
1721 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
1723 return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0,
1724 LR_SHARED | LR_DEFAULTSIZE );
1727 /***********************************************************************
1728 * LoadCursorFromFileW (USER32.361)
1730 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
1732 return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0,
1733 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1736 /***********************************************************************
1737 * LoadCursorFromFileA (USER32.360)
1739 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
1741 return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0,
1742 LR_LOADFROMFILE | LR_DEFAULTSIZE );
1745 /***********************************************************************
1746 * LoadIconW (USER32.364)
1748 HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
1750 return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0,
1751 LR_SHARED | LR_DEFAULTSIZE );
1754 /***********************************************************************
1755 * LoadIconA (USER32.363)
1757 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
1759 return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0,
1760 LR_SHARED | LR_DEFAULTSIZE );
1763 /**********************************************************************
1764 * GetIconInfo16 (USER.395)
1766 BOOL16 WINAPI GetIconInfo16(HICON16 hIcon,LPICONINFO16 iconinfo)
1768 ICONINFO ii32;
1769 BOOL16 ret = GetIconInfo((HICON)hIcon, &ii32);
1771 iconinfo->fIcon = ii32.fIcon;
1772 iconinfo->xHotspot = ii32.xHotspot;
1773 iconinfo->yHotspot = ii32.yHotspot;
1774 iconinfo->hbmMask = ii32.hbmMask;
1775 iconinfo->hbmColor = ii32.hbmColor;
1776 return ret;
1779 /**********************************************************************
1780 * GetIconInfo32 (USER32.242)
1782 BOOL WINAPI GetIconInfo(HICON hIcon,LPICONINFO iconinfo) {
1783 CURSORICONINFO *ciconinfo;
1785 ciconinfo = GlobalLock16(hIcon);
1786 if (!ciconinfo)
1787 return FALSE;
1789 if ( (ciconinfo->ptHotSpot.x == ICON_HOTSPOT) &&
1790 (ciconinfo->ptHotSpot.y == ICON_HOTSPOT) )
1792 iconinfo->fIcon = TRUE;
1793 iconinfo->xHotspot = 0;
1794 iconinfo->yHotspot = 0;
1796 else
1798 iconinfo->fIcon = FALSE;
1799 iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
1800 iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
1803 iconinfo->hbmColor = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1804 ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
1805 (char *)(ciconinfo + 1)
1806 + ciconinfo->nHeight *
1807 BITMAP_GetWidthBytes (ciconinfo->nWidth,1) );
1808 iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, ciconinfo->nHeight,
1809 1, 1, (char *)(ciconinfo + 1));
1811 GlobalUnlock16(hIcon);
1813 return TRUE;
1816 /**********************************************************************
1817 * CreateIconIndirect (USER32.78)
1819 HICON WINAPI CreateIconIndirect(LPICONINFO iconinfo) {
1820 BITMAPOBJ *bmpXor,*bmpAnd;
1821 HICON hObj;
1822 int sizeXor,sizeAnd;
1824 bmpXor = (BITMAPOBJ *) GDI_GetObjPtr( iconinfo->hbmColor, BITMAP_MAGIC );
1825 bmpAnd = (BITMAPOBJ *) GDI_GetObjPtr( iconinfo->hbmMask, BITMAP_MAGIC );
1827 sizeXor = bmpXor->bitmap.bmHeight * bmpXor->bitmap.bmWidthBytes;
1828 sizeAnd = bmpAnd->bitmap.bmHeight * bmpAnd->bitmap.bmWidthBytes;
1830 hObj = GlobalAlloc16( GMEM_MOVEABLE,
1831 sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
1832 if (hObj)
1834 CURSORICONINFO *info;
1836 info = (CURSORICONINFO *)GlobalLock16( hObj );
1838 /* If we are creating an icon, the hotspot is unused */
1839 if (iconinfo->fIcon)
1841 info->ptHotSpot.x = ICON_HOTSPOT;
1842 info->ptHotSpot.y = ICON_HOTSPOT;
1844 else
1846 info->ptHotSpot.x = iconinfo->xHotspot;
1847 info->ptHotSpot.y = iconinfo->yHotspot;
1850 info->nWidth = bmpXor->bitmap.bmWidth;
1851 info->nHeight = bmpXor->bitmap.bmHeight;
1852 info->nWidthBytes = bmpXor->bitmap.bmWidthBytes;
1853 info->bPlanes = bmpXor->bitmap.bmPlanes;
1854 info->bBitsPerPixel = bmpXor->bitmap.bmBitsPixel;
1856 /* Transfer the bitmap bits to the CURSORICONINFO structure */
1858 GetBitmapBits( iconinfo->hbmMask ,sizeAnd,(char*)(info + 1) );
1859 GetBitmapBits( iconinfo->hbmColor,sizeXor,(char*)(info + 1) +sizeAnd);
1860 GlobalUnlock16( hObj );
1862 return hObj;
1866 /**********************************************************************
1868 DrawIconEx16 (USER.394)
1870 BOOL16 WINAPI DrawIconEx16 (HDC16 hdc, INT16 xLeft, INT16 yTop, HICON16 hIcon,
1871 INT16 cxWidth, INT16 cyWidth, UINT16 istep,
1872 HBRUSH16 hbr, UINT16 flags)
1874 return DrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
1875 istep, hbr, flags);
1879 /******************************************************************************
1880 * DrawIconEx32 [USER32.160] Draws an icon or cursor on device context
1882 * NOTES
1883 * Why is this using SM_CXICON instead of SM_CXCURSOR?
1885 * PARAMS
1886 * hdc [I] Handle to device context
1887 * x0 [I] X coordinate of upper left corner
1888 * y0 [I] Y coordinate of upper left corner
1889 * hIcon [I] Handle to icon to draw
1890 * cxWidth [I] Width of icon
1891 * cyWidth [I] Height of icon
1892 * istep [I] Index of frame in animated cursor
1893 * hbr [I] Handle to background brush
1894 * flags [I] Icon-drawing flags
1896 * RETURNS
1897 * Success: TRUE
1898 * Failure: FALSE
1900 BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
1901 INT cxWidth, INT cyWidth, UINT istep,
1902 HBRUSH hbr, UINT flags )
1904 CURSORICONINFO *ptr = (CURSORICONINFO *)GlobalLock16 (hIcon);
1905 HDC hDC_off = 0, hMemDC = CreateCompatibleDC (hdc);
1906 BOOL result = FALSE, DoOffscreen = FALSE;
1907 HBITMAP hB_off = 0, hOld = 0;
1909 if (!ptr) return FALSE;
1911 if (istep)
1912 FIXME_(icon)("Ignoring istep=%d\n", istep);
1913 if (flags & DI_COMPAT)
1914 FIXME_(icon)("Ignoring flag DI_COMPAT\n");
1916 /* Calculate the size of the destination image. */
1917 if (cxWidth == 0)
1919 if (flags & DI_DEFAULTSIZE)
1920 cxWidth = GetSystemMetrics (SM_CXICON);
1921 else
1922 cxWidth = ptr->nWidth;
1924 if (cyWidth == 0)
1926 if (flags & DI_DEFAULTSIZE)
1927 cyWidth = GetSystemMetrics (SM_CYICON);
1928 else
1929 cyWidth = ptr->nHeight;
1932 if (!(DoOffscreen = (hbr >= STOCK_WHITE_BRUSH) && (hbr <=
1933 STOCK_HOLLOW_BRUSH)))
1935 GDIOBJHDR *object = (GDIOBJHDR *) GDI_HEAP_LOCK(hbr);
1936 if (object)
1938 UINT16 magic = object->wMagic;
1939 GDI_HEAP_UNLOCK(hbr);
1940 DoOffscreen = magic == BRUSH_MAGIC;
1943 if (DoOffscreen) {
1944 RECT r;
1946 r.left = 0;
1947 r.top = 0;
1948 r.right = cxWidth;
1949 r.bottom = cxWidth;
1951 hDC_off = CreateCompatibleDC(hdc);
1952 hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth);
1953 if (hDC_off && hB_off) {
1954 hOld = SelectObject(hDC_off, hB_off);
1955 FillRect(hDC_off, &r, hbr);
1959 if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
1961 HBITMAP hXorBits, hAndBits;
1962 COLORREF oldFg, oldBg;
1963 INT nStretchMode;
1965 nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
1967 hXorBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1968 ptr->bPlanes, ptr->bBitsPerPixel,
1969 (char *)(ptr + 1)
1970 + ptr->nHeight *
1971 BITMAP_GetWidthBytes(ptr->nWidth,1) );
1972 hAndBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
1973 1, 1, (char *)(ptr+1) );
1974 oldFg = SetTextColor( hdc, RGB(0,0,0) );
1975 oldBg = SetBkColor( hdc, RGB(255,255,255) );
1977 if (hXorBits && hAndBits)
1979 HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
1980 if (flags & DI_MASK)
1982 if (DoOffscreen)
1983 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1984 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1985 else
1986 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
1987 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
1989 SelectObject( hMemDC, hXorBits );
1990 if (flags & DI_IMAGE)
1992 if (DoOffscreen)
1993 StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
1994 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
1995 else
1996 StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
1997 hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
1999 SelectObject( hMemDC, hBitTemp );
2000 result = TRUE;
2003 SetTextColor( hdc, oldFg );
2004 SetBkColor( hdc, oldBg );
2005 if (hXorBits) DeleteObject( hXorBits );
2006 if (hAndBits) DeleteObject( hAndBits );
2007 SetStretchBltMode (hdc, nStretchMode);
2008 if (DoOffscreen) {
2009 BitBlt(hdc, x0, y0, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
2010 SelectObject(hDC_off, hOld);
2013 if (hMemDC) DeleteDC( hMemDC );
2014 if (hDC_off) DeleteDC(hDC_off);
2015 if (hB_off) DeleteObject(hB_off);
2016 GlobalUnlock16( hIcon );
2017 return result;