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