2 * PROJECT: ReactOS user32.dll
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/user32/windows/cursoricon.c
5 * PURPOSE: cursor and icons implementation
6 * PROGRAMMER: Jérôme Gardou (jerome.gardou@reactos.org)
11 #include <wine/debug.h>
13 WINE_DEFAULT_DEBUG_CHANNEL(cursor
);
14 WINE_DECLARE_DEBUG_CHANNEL(icon
);
15 //WINE_DECLARE_DEBUG_CHANNEL(resource);
17 /************* USER32 INTERNAL FUNCTIONS **********/
19 /* This callback routine is called directly after switching to gui mode */
22 User32SetupDefaultCursors(PVOID Arguments
,
25 BOOL
*DefaultCursor
= (BOOL
*)Arguments
;
30 /* set default cursor */
31 hCursor
= LoadCursorW(0, (LPCWSTR
)IDC_ARROW
);
36 /* FIXME load system cursor scheme */
38 hCursor
= LoadCursorW(0, (LPCWSTR
)IDC_ARROW
);
42 return(ZwCallbackReturn(&hCursor
, sizeof(HCURSOR
), STATUS_SUCCESS
));
45 BOOL
get_icon_size(HICON hIcon
, SIZE
*size
)
47 return NtUserGetIconSize(hIcon
, 0, &size
->cx
, &size
->cy
);
50 HCURSOR
CursorIconToCursor(HICON hIcon
, BOOL SemiTransparent
)
56 /************* IMPLEMENTATION HELPERS ******************/
58 static const WCHAR DISPLAYW
[] = L
"DISPLAY";
60 static void *map_fileW( LPCWSTR name
, LPDWORD filesize
)
62 HANDLE hFile
, hMapping
;
65 hFile
= CreateFileW( name
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
66 OPEN_EXISTING
, FILE_FLAG_RANDOM_ACCESS
, 0 );
67 if (hFile
!= INVALID_HANDLE_VALUE
)
69 hMapping
= CreateFileMappingW( hFile
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
72 ptr
= MapViewOfFile( hMapping
, FILE_MAP_READ
, 0, 0, 0 );
73 CloseHandle( hMapping
);
75 *filesize
= GetFileSize( hFile
, NULL
);
82 static int get_dib_image_size( int width
, int height
, int depth
)
84 return (((width
* depth
+ 31) / 8) & ~3) * abs( height
);
87 static BOOL
is_dib_monochrome( const BITMAPINFO
* info
)
89 if (info
->bmiHeader
.biBitCount
!= 1) return FALSE
;
91 if (info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
93 const RGBTRIPLE
*rgb
= ((const BITMAPCOREINFO
*)info
)->bmciColors
;
95 /* Check if the first color is black */
96 if ((rgb
->rgbtRed
== 0) && (rgb
->rgbtGreen
== 0) && (rgb
->rgbtBlue
== 0))
100 /* Check if the second color is white */
101 return ((rgb
->rgbtRed
== 0xff) && (rgb
->rgbtGreen
== 0xff)
102 && (rgb
->rgbtBlue
== 0xff));
106 else /* assume BITMAPINFOHEADER */
108 const RGBQUAD
*rgb
= info
->bmiColors
;
110 /* Check if the first color is black */
111 if ((rgb
->rgbRed
== 0) && (rgb
->rgbGreen
== 0) &&
112 (rgb
->rgbBlue
== 0) && (rgb
->rgbReserved
== 0))
116 /* Check if the second color is white */
117 return ((rgb
->rgbRed
== 0xff) && (rgb
->rgbGreen
== 0xff)
118 && (rgb
->rgbBlue
== 0xff) && (rgb
->rgbReserved
== 0));
124 static int bitmap_info_size( const BITMAPINFO
* info
, WORD coloruse
)
126 unsigned int colors
, size
, masks
= 0;
128 if (info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
130 const BITMAPCOREHEADER
*core
= (const BITMAPCOREHEADER
*)info
;
131 colors
= (core
->bcBitCount
<= 8) ? 1 << core
->bcBitCount
: 0;
132 return sizeof(BITMAPCOREHEADER
) + colors
*
133 ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBTRIPLE
) : sizeof(WORD
));
135 else /* assume BITMAPINFOHEADER */
137 colors
= info
->bmiHeader
.biClrUsed
;
138 if (colors
> 256) /* buffer overflow otherwise */
140 if (!colors
&& (info
->bmiHeader
.biBitCount
<= 8))
141 colors
= 1 << info
->bmiHeader
.biBitCount
;
142 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
) masks
= 3;
143 size
= max( info
->bmiHeader
.biSize
, sizeof(BITMAPINFOHEADER
) + masks
* sizeof(DWORD
) );
144 return size
+ colors
* ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBQUAD
) : sizeof(WORD
));
148 static int DIB_GetBitmapInfo( const BITMAPINFOHEADER
*header
, LONG
*width
,
149 LONG
*height
, WORD
*bpp
, DWORD
*compr
)
151 if (header
->biSize
== sizeof(BITMAPCOREHEADER
))
153 const BITMAPCOREHEADER
*core
= (const BITMAPCOREHEADER
*)header
;
154 *width
= core
->bcWidth
;
155 *height
= core
->bcHeight
;
156 *bpp
= core
->bcBitCount
;
160 else if (header
->biSize
== sizeof(BITMAPINFOHEADER
) ||
161 header
->biSize
== sizeof(BITMAPV4HEADER
) ||
162 header
->biSize
== sizeof(BITMAPV5HEADER
))
164 *width
= header
->biWidth
;
165 *height
= header
->biHeight
;
166 *bpp
= header
->biBitCount
;
167 *compr
= header
->biCompression
;
170 ERR("(%d): unknown/wrong size for header\n", header
->biSize
);
174 /***********************************************************************
177 static BOOL
bmi_has_alpha( const BITMAPINFO
*info
, const void *bits
)
180 BOOL has_alpha
= FALSE
;
181 const unsigned char *ptr
= bits
;
183 if (info
->bmiHeader
.biBitCount
!= 32) return FALSE
;
184 for (i
= 0; i
< info
->bmiHeader
.biWidth
* abs(info
->bmiHeader
.biHeight
); i
++, ptr
+= 4)
185 if ((has_alpha
= (ptr
[3] != 0))) break;
189 /***********************************************************************
190 * create_alpha_bitmap
192 * Create the alpha bitmap for a 32-bpp icon that has an alpha channel.
194 static HBITMAP
create_alpha_bitmap(
196 _In_opt_
const BITMAPINFO
*src_info
,
197 _In_opt_
const void *color_bits
)
199 HBITMAP alpha
= NULL
, hbmpOld
;
200 BITMAPINFO
*info
= NULL
;
201 HDC hdc
= NULL
, hdcScreen
;
208 if (!GetObjectW( color
, sizeof(bm
), &bm
))
210 if (bm
.bmBitsPixel
!= 32)
213 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
216 if(GetDeviceCaps(hdcScreen
, BITSPIXEL
) != 32)
218 hdc
= CreateCompatibleDC(hdcScreen
);
228 if(!bmi_has_alpha(src_info
, color_bits
))
231 if(!DIB_GetBitmapInfo(&src_info
->bmiHeader
, &width
, &height
, &bpp
, &compr
))
236 size
= get_dib_image_size(width
, height
, bpp
);
237 bits
= HeapAlloc(GetProcessHeap(), 0, size
);
240 CopyMemory(bits
, color_bits
, size
);
244 info
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(BITMAPINFO
, bmiColors
[256]));
247 info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
248 info
->bmiHeader
.biWidth
= bm
.bmWidth
;
249 info
->bmiHeader
.biHeight
= -bm
.bmHeight
;
250 info
->bmiHeader
.biPlanes
= 1;
251 info
->bmiHeader
.biBitCount
= 32;
252 info
->bmiHeader
.biCompression
= BI_RGB
;
253 info
->bmiHeader
.biSizeImage
= bm
.bmWidth
* bm
.bmHeight
* 4;
254 info
->bmiHeader
.biXPelsPerMeter
= 0;
255 info
->bmiHeader
.biYPelsPerMeter
= 0;
256 info
->bmiHeader
.biClrUsed
= 0;
257 info
->bmiHeader
.biClrImportant
= 0;
259 bits
= HeapAlloc(GetProcessHeap(), 0, info
->bmiHeader
.biSizeImage
);
262 if(!GetDIBits( hdc
, color
, 0, bm
.bmHeight
, bits
, info
, DIB_RGB_COLORS
))
264 if (!bmi_has_alpha( info
, bits
))
267 height
= bm
.bmHeight
;
270 /* pre-multiply by alpha */
271 for (i
= 0, ptr
= bits
; i
< width
* height
; i
++, ptr
+= 4)
273 unsigned int alpha
= ptr
[3];
274 ptr
[0] = ptr
[0] * alpha
/ 255;
275 ptr
[1] = ptr
[1] * alpha
/ 255;
276 ptr
[2] = ptr
[2] * alpha
/ 255;
279 /* Create the bitmap */
280 alpha
= CreateCompatibleBitmap(hdcScreen
, bm
.bmWidth
, bm
.bmHeight
);
283 hbmpOld
= SelectObject(hdc
, alpha
);
286 if(!StretchDIBits( hdc
, 0, 0, bm
.bmWidth
, bm
.bmHeight
,
288 bits
, src_info
? src_info
: info
, DIB_RGB_COLORS
, SRCCOPY
))
290 SelectObject(hdc
, hbmpOld
);
295 SelectObject(hdc
, hbmpOld
);
299 if(hdc
) DeleteDC( hdc
);
300 if(info
) HeapFree( GetProcessHeap(), 0, info
);
301 if(bits
) HeapFree(GetProcessHeap(), 0, bits
);
303 TRACE("Returning 0x%08x.\n", alpha
);
307 /************* IMPLEMENTATION CORE ****************/
309 static BOOL
CURSORICON_GetCursorDataFromBMI(
310 _Inout_ CURSORDATA
* pdata
,
311 _In_
const BITMAPINFO
*pbmi
314 UINT ubmiSize
= bitmap_info_size(pbmi
, DIB_RGB_COLORS
);
315 BOOL monochrome
= is_dib_monochrome(pbmi
);
321 BITMAPINFO
* pbmiCopy
;
322 HBITMAP hbmpOld
= NULL
;
323 BOOL bResult
= FALSE
;
324 const VOID
*pvColor
, *pvMask
;
326 ibmpType
= DIB_GetBitmapInfo(&pbmi
->bmiHeader
, &width
, &height
, &bpp
, &compr
);
331 /* No compression for icons */
335 /* If no dimensions were set, use the one from the icon */
336 if(!pdata
->cx
) pdata
->cx
= width
;
337 if(!pdata
->cy
) pdata
->cy
= height
< 0 ? -height
/2 : height
/2;
339 /* Fix the hotspot coords */
340 if(pdata
->rt
== (USHORT
)((ULONG_PTR
)RT_CURSOR
))
342 if(pdata
->cx
!= width
)
343 pdata
->xHotspot
= (pdata
->xHotspot
* pdata
->cx
) / width
;
344 if(pdata
->cy
!= height
/2)
345 pdata
->yHotspot
= (pdata
->yHotspot
* pdata
->cy
* 2) / height
;
349 pdata
->xHotspot
= pdata
->cx
/2;
350 pdata
->yHotspot
= pdata
->cy
/2;
353 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
356 hdc
= CreateCompatibleDC(hdcScreen
);
363 pbmiCopy
= HeapAlloc(GetProcessHeap(), 0, max(ubmiSize
, FIELD_OFFSET(BITMAPINFO
, bmiColors
[3])));
366 RtlCopyMemory(pbmiCopy
, pbmi
, ubmiSize
);
368 /* In an icon/cursor, the BITMAPINFO holds twice the height */
369 if(pbmiCopy
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
370 ((BITMAPCOREHEADER
*)&pbmiCopy
->bmiHeader
)->bcHeight
/= 2;
372 pbmiCopy
->bmiHeader
.biHeight
/= 2;
375 pvColor
= (const char*)pbmi
+ ubmiSize
;
376 pvMask
= (const char*)pvColor
+
377 get_dib_image_size(width
, height
, bpp
);
382 /* Create the 1bpp bitmap which will contain everything */
383 pdata
->hbmColor
= NULL
;
384 pdata
->hbmMask
= CreateBitmap(pdata
->cx
, pdata
->cy
* 2, 1, 1, NULL
);
387 hbmpOld
= SelectObject(hdc
, pdata
->hbmMask
);
391 if(!StretchDIBits(hdc
, 0, pdata
->cy
, pdata
->cx
, pdata
->cy
,
393 pvColor
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
))
399 /* Create the bitmap. It has to be compatible with the screen surface */
400 pdata
->hbmColor
= CreateCompatibleBitmap(hdcScreen
, pdata
->cx
, pdata
->cy
);
403 /* Create the 1bpp mask bitmap */
404 pdata
->hbmMask
= CreateBitmap(pdata
->cx
, pdata
->cy
, 1, 1, NULL
);
407 hbmpOld
= SelectObject(hdc
, pdata
->hbmColor
);
410 if(!StretchDIBits(hdc
, 0, 0, pdata
->cx
, pdata
->cy
,
412 pvColor
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
))
414 pdata
->bpp
= GetDeviceCaps(hdcScreen
, BITSPIXEL
);
416 pdata
->hbmAlpha
= create_alpha_bitmap(pdata
->hbmColor
, pbmiCopy
, pvColor
);
418 /* Now convert the info to monochrome for the mask bits */
419 if (pbmiCopy
->bmiHeader
.biSize
!= sizeof(BITMAPCOREHEADER
))
421 RGBQUAD
*rgb
= pbmiCopy
->bmiColors
;
423 pbmiCopy
->bmiHeader
.biClrUsed
= pbmiCopy
->bmiHeader
.biClrImportant
= 2;
424 rgb
[0].rgbBlue
= rgb
[0].rgbGreen
= rgb
[0].rgbRed
= 0x00;
425 rgb
[1].rgbBlue
= rgb
[1].rgbGreen
= rgb
[1].rgbRed
= 0xff;
426 rgb
[0].rgbReserved
= rgb
[1].rgbReserved
= 0;
427 pbmiCopy
->bmiHeader
.biBitCount
= 1;
431 RGBTRIPLE
*rgb
= (RGBTRIPLE
*)(((BITMAPCOREHEADER
*)pbmiCopy
) + 1);
433 rgb
[0].rgbtBlue
= rgb
[0].rgbtGreen
= rgb
[0].rgbtRed
= 0x00;
434 rgb
[1].rgbtBlue
= rgb
[1].rgbtGreen
= rgb
[1].rgbtRed
= 0xff;
435 ((BITMAPCOREHEADER
*)&pbmiCopy
->bmiHeader
)->bcBitCount
= 1;
438 /* Set the mask bits */
439 if(!SelectObject(hdc
, pdata
->hbmMask
))
441 bResult
= StretchDIBits(hdc
, 0, 0, pdata
->cx
, pdata
->cy
,
443 pvMask
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
) != 0;
447 if(hbmpOld
) SelectObject(hdc
, hbmpOld
);
449 if(pbmiCopy
) HeapFree(GetProcessHeap(), 0, pbmiCopy
);
450 /* Clean up in case of failure */
453 if(pdata
->hbmMask
) DeleteObject(pdata
->hbmMask
);
454 if(pdata
->hbmColor
) DeleteObject(pdata
->hbmColor
);
455 if(pdata
->hbmAlpha
) DeleteObject(pdata
->hbmAlpha
);
460 static BOOL
CURSORICON_GetCursorDataFromIconInfo(
461 _Out_ CURSORDATA
* pCursorData
,
462 _In_ ICONINFO
* pIconInfo
467 ZeroMemory(pCursorData
, sizeof(*pCursorData
));
468 /* Use the CopyImage function, as it will gracefully convert our bitmap to the screen bit depth */
469 if(pIconInfo
->hbmColor
)
471 pCursorData
->hbmColor
= CopyImage(pIconInfo
->hbmColor
, IMAGE_BITMAP
, 0, 0, 0);
472 if(!pCursorData
->hbmColor
)
475 pCursorData
->hbmMask
= CopyImage(pIconInfo
->hbmMask
, IMAGE_BITMAP
, 0, 0, LR_MONOCHROME
);
476 if(!pCursorData
->hbmMask
)
479 /* Now, fill some information */
480 pCursorData
->rt
= (USHORT
)((ULONG_PTR
)(pIconInfo
->fIcon
? RT_ICON
: RT_CURSOR
));
481 if(pCursorData
->hbmColor
)
483 GetObject(pCursorData
->hbmColor
, sizeof(bm
), &bm
);
484 pCursorData
->bpp
= bm
.bmBitsPixel
;
485 pCursorData
->cx
= bm
.bmWidth
;
486 pCursorData
->cy
= bm
.bmHeight
;
487 if(pCursorData
->bpp
== 32)
488 pCursorData
->hbmAlpha
= create_alpha_bitmap(pCursorData
->hbmColor
, NULL
, NULL
);
492 GetObject(pCursorData
->hbmMask
, sizeof(bm
), &bm
);
493 pCursorData
->bpp
= 1;
494 pCursorData
->cx
= bm
.bmWidth
;
495 pCursorData
->cy
= bm
.bmHeight
/2;
500 pCursorData
->xHotspot
= pCursorData
->cx
/2;
501 pCursorData
->yHotspot
= pCursorData
->cy
/2;
505 pCursorData
->xHotspot
= pIconInfo
->xHotspot
;
506 pCursorData
->yHotspot
= pIconInfo
->yHotspot
;
515 _In_opt_ HINSTANCE hinst
,
516 _In_ LPCWSTR lpszName
,
522 const BITMAPINFO
* pbmi
;
523 BITMAPINFO
* pbmiScaled
= NULL
;
524 BITMAPINFO
* pbmiCopy
= NULL
;
525 const VOID
* pvMapping
= NULL
;
527 HGLOBAL hgRsrc
= NULL
;
530 HDC hdcScreen
= NULL
;
532 HBITMAP hbmpOld
, hbmpRet
= NULL
;
537 /* Map the bitmap info */
538 if(fuLoad
& LR_LOADFROMFILE
)
540 const BITMAPFILEHEADER
* pbmfh
;
542 pvMapping
= map_fileW(lpszName
, NULL
);
546 if (pbmfh
->bfType
!= 0x4d42 /* 'BM' */)
548 WARN("Invalid/unsupported bitmap format!\n");
551 pbmi
= (const BITMAPINFO
*)(pbmfh
+ 1);
553 /* Get the image bits */
555 dwOffset
= pbmfh
->bfOffBits
- sizeof(BITMAPFILEHEADER
);
561 /* Caller wants an OEM bitmap */
563 hinst
= User32Instance
;
564 hrsrc
= FindResourceW(hinst
, lpszName
, (LPWSTR
)RT_BITMAP
);
567 hgRsrc
= LoadResource(hinst
, hrsrc
);
570 pbmi
= LockResource(hgRsrc
);
576 if(DIB_GetBitmapInfo(&pbmi
->bmiHeader
, &width
, &height
, &bpp
, &compr
) == -1)
578 if((width
> 65535) || (height
> 65535))
585 cyDesired
= -cyDesired
;
587 iBMISize
= bitmap_info_size(pbmi
, DIB_RGB_COLORS
);
589 /* Get a pointer to the image data */
590 pvBits
= (char*)pbmi
+ (dwOffset
? dwOffset
: iBMISize
);
592 /* Create a copy of the info describing the bitmap in the file */
593 pbmiCopy
= HeapAlloc(GetProcessHeap(), 0, iBMISize
);
596 CopyMemory(pbmiCopy
, pbmi
, iBMISize
);
598 /* Fix it up, if needed */
599 if(fuLoad
& (LR_LOADTRANSPARENT
| LR_LOADMAP3DCOLORS
))
601 WORD bpp
, incr
, numColors
;
604 COLORREF crWindow
, cr3DShadow
, cr3DFace
, cr3DLight
;
605 BYTE pixel
= *((BYTE
*)pvBits
);
608 if(pbmiCopy
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
610 bpp
= ((BITMAPCOREHEADER
*)&pbmiCopy
->bmiHeader
)->bcBitCount
;
611 numColors
= 1 << bpp
;
612 /* BITMAPCOREINFO holds RGBTRIPLEs */
617 bpp
= pbmiCopy
->bmiHeader
.biBitCount
;
618 /* BITMAPINFOHEADER holds RGBQUADs */
620 numColors
= pbmiCopy
->bmiHeader
.biClrUsed
;
621 if(numColors
> 256) numColors
= 256;
622 if (!numColors
&& (bpp
<= 8)) numColors
= 1 << bpp
;
628 pbmiColors
= (char*)pbmiCopy
+ pbmiCopy
->bmiHeader
.biSize
;
630 /* Get the relevant colors */
631 crWindow
= GetSysColor(COLOR_WINDOW
);
632 cr3DShadow
= GetSysColor(COLOR_3DSHADOW
);
633 cr3DFace
= GetSysColor(COLOR_3DFACE
);
634 cr3DLight
= GetSysColor(COLOR_3DLIGHT
);
636 /* Fix the transparent palette entry */
637 if(fuLoad
& LR_LOADTRANSPARENT
)
641 case 1: pixel
>>= 7; break;
642 case 4: pixel
>>= 4; break;
645 FIXME("Unhandled bit depth %d.\n", bpp
);
649 if(pixel
>= numColors
)
651 ERR("Wrong pixel passed in.\n");
655 /* If both flags are set, we must use COLOR_3DFACE */
656 if(fuLoad
& LR_LOADMAP3DCOLORS
) crWindow
= cr3DFace
;
658 /* Define the color */
659 ptr
= (RGBTRIPLE
*)(pbmiColors
+ pixel
*incr
);
660 ptr
->rgbtBlue
= GetBValue(crWindow
);
661 ptr
->rgbtGreen
= GetGValue(crWindow
);
662 ptr
->rgbtRed
= GetRValue(crWindow
);
666 /* If we are here, then LR_LOADMAP3DCOLORS is set without LR_TRANSPARENT */
667 for(i
= 0; i
<numColors
; i
++)
669 ptr
= (RGBTRIPLE
*)(pbmiColors
+ i
*incr
);
670 if((ptr
->rgbtBlue
== ptr
->rgbtRed
) && (ptr
->rgbtBlue
== ptr
->rgbtGreen
))
672 if(ptr
->rgbtBlue
== 128)
674 ptr
->rgbtBlue
= GetBValue(cr3DShadow
);
675 ptr
->rgbtGreen
= GetGValue(cr3DShadow
);
676 ptr
->rgbtRed
= GetRValue(cr3DShadow
);
678 if(ptr
->rgbtBlue
== 192)
680 ptr
->rgbtBlue
= GetBValue(cr3DFace
);
681 ptr
->rgbtGreen
= GetGValue(cr3DFace
);
682 ptr
->rgbtRed
= GetRValue(cr3DFace
);
684 if(ptr
->rgbtBlue
== 223)
686 ptr
->rgbtBlue
= GetBValue(cr3DLight
);
687 ptr
->rgbtGreen
= GetGValue(cr3DLight
);
688 ptr
->rgbtRed
= GetRValue(cr3DLight
);
695 if(fuLoad
& LR_CREATEDIBSECTION
)
697 /* Allocate the BMI describing the new bitmap */
698 pbmiScaled
= HeapAlloc(GetProcessHeap(), 0, iBMISize
);
701 CopyMemory(pbmiScaled
, pbmiCopy
, iBMISize
);
704 if(pbmiScaled
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
706 BITMAPCOREHEADER
* pbmch
= (BITMAPCOREHEADER
*)&pbmiScaled
->bmiHeader
;
707 pbmch
->bcWidth
= cxDesired
;
708 pbmch
->bcHeight
= cyDesired
;
712 pbmiScaled
->bmiHeader
.biWidth
= cxDesired
;
713 pbmiScaled
->bmiHeader
.biHeight
= cyDesired
;
714 /* No compression for DIB sections */
715 pbmiScaled
->bmiHeader
.biCompression
= BI_RGB
;
720 if(cyDesired
< 0) cyDesired
= -cyDesired
;
722 /* We need a device context */
723 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
726 hdc
= CreateCompatibleDC(hdcScreen
);
730 /* Now create the bitmap */
731 if(fuLoad
& LR_CREATEDIBSECTION
)
732 hbmpRet
= CreateDIBSection(hdc
, pbmiScaled
, DIB_RGB_COLORS
, NULL
, 0, 0);
735 if(is_dib_monochrome(pbmiCopy
) || (fuLoad
& LR_MONOCHROME
))
736 hbmpRet
= CreateBitmap(cxDesired
, cyDesired
, 1, 1, NULL
);
738 hbmpRet
= CreateCompatibleBitmap(hdcScreen
, cxDesired
, cyDesired
);
744 hbmpOld
= SelectObject(hdc
, hbmpRet
);
747 if(!StretchDIBits(hdc
, 0, 0, cxDesired
, cyDesired
,
748 0, 0, pbmi
->bmiHeader
.biWidth
, pbmi
->bmiHeader
.biWidth
,
749 pvBits
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
))
751 ERR("StretchDIBits failed!.\n");
752 SelectObject(hdc
, hbmpOld
);
753 DeleteObject(hbmpRet
);
758 SelectObject(hdc
, hbmpOld
);
766 HeapFree(GetProcessHeap(), 0, pbmiScaled
);
768 HeapFree(GetProcessHeap(), 0, pbmiCopy
);
770 UnmapViewOfFile( pvMapping
);
772 FreeResource(hgRsrc
);
777 #include "pshpack1.h"
788 } CURSORICONFILEDIRENTRY
;
795 CURSORICONFILEDIRENTRY idEntries
[1];
802 CURSORICON_LoadFromFileW(
803 _In_ LPCWSTR lpszName
,
810 CURSORICONDIR
* fakeDir
;
811 CURSORICONDIRENTRY
* fakeEntry
;
812 CURSORICONFILEDIRENTRY
*entry
;
813 CURSORICONFILEDIR
*dir
;
816 HANDLE hCurIcon
= NULL
;
818 CURSORDATA cursorData
;
820 TRACE("loading %s\n", debugstr_w( lpszName
));
822 bits
= map_fileW( lpszName
, &filesize
);
826 /* Check for .ani. */
827 if (memcmp( bits
, "RIFF", 4 ) == 0)
833 dir
= (CURSORICONFILEDIR
*) bits
;
834 if ( filesize
< sizeof(*dir
) )
837 if ( filesize
< (sizeof(*dir
) + sizeof(dir
->idEntries
[0])*(dir
->idCount
-1)) )
842 * We allocate a buffer, fake it as if it was a pointer to a resource in a module,
843 * pass it to LookupIconIdFromDirectoryEx and get back the index we have to use
845 fakeDir
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(CURSORICONDIR
, idEntries
[dir
->idCount
]));
848 fakeDir
->idReserved
= 0;
849 fakeDir
->idType
= dir
->idType
;
850 fakeDir
->idCount
= dir
->idCount
;
851 for(i
= 0; i
<dir
->idCount
; i
++)
853 fakeEntry
= &fakeDir
->idEntries
[i
];
854 entry
= &dir
->idEntries
[i
];
855 /* Take this as an occasion to perform a size check */
856 if((entry
->dwDIBOffset
+ entry
->dwDIBSize
) > filesize
)
858 /* File icon/cursors are not like resource ones */
861 fakeEntry
->ResInfo
.icon
.bWidth
= entry
->bWidth
;
862 fakeEntry
->ResInfo
.icon
.bHeight
= entry
->bHeight
;
863 fakeEntry
->ResInfo
.icon
.bColorCount
= 0;
864 fakeEntry
->ResInfo
.icon
.bReserved
= 0;
868 fakeEntry
->ResInfo
.cursor
.wWidth
= entry
->bWidth
;
869 fakeEntry
->ResInfo
.cursor
.wHeight
= entry
->bHeight
;
871 /* Let's assume there's always one plane */
872 fakeEntry
->wPlanes
= 1;
873 /* We must get the bitcount from the BITMAPINFOHEADER itself */
874 fakeEntry
->wBitCount
= ((BITMAPINFOHEADER
*)((char *)dir
+ entry
->dwDIBOffset
))->biBitCount
;
875 fakeEntry
->dwBytesInRes
= entry
->dwDIBSize
;
876 fakeEntry
->wResId
= i
+ 1;
879 /* Now call LookupIconIdFromResourceEx */
880 i
= LookupIconIdFromDirectoryEx((PBYTE
)fakeDir
, bIcon
, cxDesired
, cyDesired
, fuLoad
& LR_MONOCHROME
);
881 /* We don't need this anymore */
882 HeapFree(GetProcessHeap(), 0, fakeDir
);
885 WARN("Unable to get a fit entry index.\n");
890 entry
= &dir
->idEntries
[i
-1];
892 if(!cxDesired
) cxDesired
= entry
->bWidth
;
893 if(!cyDesired
) cyDesired
= entry
->bHeight
;
894 /* A bit of preparation */
895 ZeroMemory(&cursorData
, sizeof(cursorData
));
898 cursorData
.xHotspot
= entry
->xHotspot
;
899 cursorData
.yHotspot
= entry
->yHotspot
;
901 cursorData
.rt
= (USHORT
)((ULONG_PTR
)(bIcon
? RT_ICON
: RT_CURSOR
));
904 if(!CURSORICON_GetCursorDataFromBMI(&cursorData
, (BITMAPINFO
*)&bits
[entry
->dwDIBOffset
]))
907 hCurIcon
= NtUserxCreateEmptyCurObject(bIcon
? 0 : 1);
912 if(!NtUserSetCursorIconData(hCurIcon
, NULL
, NULL
, &cursorData
))
914 NtUserDestroyCursor(hCurIcon
, TRUE
);
919 UnmapViewOfFile(bits
);
924 DeleteObject(cursorData
.hbmMask
);
925 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
926 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
933 CURSORICON_LoadImageW(
934 _In_opt_ HINSTANCE hinst
,
935 _In_ LPCWSTR lpszName
,
943 HANDLE handle
, hCurIcon
= NULL
;
947 CURSORDATA cursorData
;
949 UNICODE_STRING ustrRsrc
;
950 UNICODE_STRING ustrModule
= {0, 0, NULL
};
952 /* Fix width/height */
953 if(fuLoad
& LR_DEFAULTSIZE
)
955 if(!cxDesired
) cxDesired
= GetSystemMetrics(bIcon
? SM_CXICON
: SM_CXCURSOR
);
956 if(!cyDesired
) cyDesired
= GetSystemMetrics(bIcon
? SM_CYICON
: SM_CYCURSOR
);
959 if(fuLoad
& LR_LOADFROMFILE
)
961 return CURSORICON_LoadFromFileW(lpszName
, cxDesired
, cyDesired
, fuLoad
, bIcon
);
964 /* Check if caller wants OEM icons */
966 hinst
= User32Instance
;
968 if(fuLoad
& LR_SHARED
)
970 DWORD size
= MAX_PATH
;
971 FINDEXISTINGCURICONPARAM param
;
973 TRACE("Checking for an LR_SHARED cursor/icon.\n");
974 /* Prepare the resource name string */
975 if(IS_INTRESOURCE(lpszName
))
977 ustrRsrc
.Buffer
= (LPWSTR
)lpszName
;
979 ustrRsrc
.MaximumLength
= 0;
982 RtlInitUnicodeString(&ustrRsrc
, lpszName
);
984 /* Prepare the module name string */
985 ustrModule
.Buffer
= HeapAlloc(GetProcessHeap(), 0, size
*sizeof(WCHAR
));
989 DWORD ret
= GetModuleFileNameW(hinst
, ustrModule
.Buffer
, size
);
992 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
997 ustrModule
.Length
= ret
*sizeof(WCHAR
);
998 ustrModule
.MaximumLength
= size
*sizeof(WCHAR
);
1002 ustrModule
.Buffer
= HeapReAlloc(GetProcessHeap(), 0, ustrModule
.Buffer
, size
*sizeof(WCHAR
));
1006 param
.bIcon
= bIcon
;
1007 param
.cx
= cxDesired
;
1008 param
.cy
= cyDesired
;
1009 hCurIcon
= NtUserFindExistingCursorIcon(&ustrModule
, &ustrRsrc
, ¶m
);
1012 /* Woohoo, got it! */
1014 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1019 /* Find resource ID */
1020 hrsrc
= FindResourceW(
1023 (LPWSTR
)(bIcon
? RT_GROUP_ICON
: RT_GROUP_CURSOR
));
1025 /* We let FindResource, LoadResource, etc. call SetLastError */
1029 handle
= LoadResource(hinst
, hrsrc
);
1033 dir
= LockResource(handle
);
1037 wResId
= LookupIconIdFromDirectoryEx((PBYTE
)dir
, bIcon
, cxDesired
, cyDesired
, fuLoad
& LR_MONOCHROME
);
1038 FreeResource(handle
);
1040 /* Get the relevant resource pointer */
1041 hrsrc
= FindResourceW(
1043 MAKEINTRESOURCEW(wResId
),
1044 (LPWSTR
)(bIcon
? RT_ICON
: RT_CURSOR
));
1048 handle
= LoadResource(hinst
, hrsrc
);
1052 bits
= LockResource(handle
);
1055 FreeResource(handle
);
1059 ZeroMemory(&cursorData
, sizeof(cursorData
));
1061 if(dir
->idType
== 2)
1063 /* idType == 2 for cursor resources */
1064 SHORT
* ptr
= (SHORT
*)bits
;
1065 cursorData
.xHotspot
= ptr
[0];
1066 cursorData
.yHotspot
= ptr
[1];
1067 bits
+= 2*sizeof(SHORT
);
1069 cursorData
.cx
= cxDesired
;
1070 cursorData
.cy
= cyDesired
;
1071 cursorData
.rt
= (USHORT
)((ULONG_PTR
)(bIcon
? RT_ICON
: RT_CURSOR
));
1073 /* Get the bitmaps */
1074 bStatus
= CURSORICON_GetCursorDataFromBMI(
1078 FreeResource( handle
);
1083 /* This is from resource */
1084 cursorData
.CURSORF_flags
= CURSORF_FROMRESOURCE
;
1086 /* Create the handle */
1087 hCurIcon
= NtUserxCreateEmptyCurObject(bIcon
? 0 : 1);
1094 if(fuLoad
& LR_SHARED
)
1096 cursorData
.CURSORF_flags
|= CURSORF_LRSHARED
;
1097 bStatus
= NtUserSetCursorIconData(hCurIcon
, &ustrModule
, &ustrRsrc
, &cursorData
);
1100 bStatus
= NtUserSetCursorIconData(hCurIcon
, NULL
, NULL
, &cursorData
);
1104 NtUserDestroyCursor(hCurIcon
, TRUE
);
1109 if(ustrModule
.Buffer
)
1110 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1114 if(ustrModule
.Buffer
)
1115 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1116 DeleteObject(cursorData
.hbmMask
);
1117 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
1118 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
1137 objSize
= GetObjectW( hnd
, sizeof(ds
), &ds
);
1138 if (!objSize
) return 0;
1139 if ((desiredx
< 0) || (desiredy
< 0)) return 0;
1141 if (flags
& LR_COPYFROMRESOURCE
)
1143 FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
1146 if (flags
& LR_COPYRETURNORG
)
1148 FIXME("The flag LR_COPYRETURNORG is not implemented for bitmaps\n");
1151 if (desiredx
== 0) desiredx
= ds
.dsBm
.bmWidth
;
1152 if (desiredy
== 0) desiredy
= ds
.dsBm
.bmHeight
;
1154 /* Allocate memory for a BITMAPINFOHEADER structure and a
1155 color table. The maximum number of colors in a color table
1156 is 256 which corresponds to a bitmap with depth 8.
1157 Bitmaps with higher depths don't have color tables. */
1158 bi
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
));
1161 bi
->bmiHeader
.biSize
= sizeof(bi
->bmiHeader
);
1162 bi
->bmiHeader
.biPlanes
= ds
.dsBm
.bmPlanes
;
1163 bi
->bmiHeader
.biBitCount
= ds
.dsBm
.bmBitsPixel
;
1164 bi
->bmiHeader
.biCompression
= BI_RGB
;
1166 if (flags
& LR_CREATEDIBSECTION
)
1168 /* Create a DIB section. LR_MONOCHROME is ignored */
1170 HDC dc
= CreateCompatibleDC(NULL
);
1172 if (objSize
== sizeof(DIBSECTION
))
1174 /* The source bitmap is a DIB.
1175 Get its attributes to create an exact copy */
1176 memcpy(bi
, &ds
.dsBmih
, sizeof(BITMAPINFOHEADER
));
1179 bi
->bmiHeader
.biWidth
= desiredx
;
1180 bi
->bmiHeader
.biHeight
= desiredy
;
1182 /* Get the color table or the color masks */
1183 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
1185 res
= CreateDIBSection(dc
, bi
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
1190 /* Create a device-dependent bitmap */
1192 BOOL monochrome
= (flags
& LR_MONOCHROME
);
1194 if (objSize
== sizeof(DIBSECTION
))
1196 /* The source bitmap is a DIB section.
1197 Get its attributes */
1198 HDC dc
= CreateCompatibleDC(NULL
);
1199 bi
->bmiHeader
.biWidth
= ds
.dsBm
.bmWidth
;
1200 bi
->bmiHeader
.biHeight
= ds
.dsBm
.bmHeight
;
1201 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
1204 if (!monochrome
&& ds
.dsBm
.bmBitsPixel
== 1)
1206 /* Look if the colors of the DIB are black and white */
1209 (bi
->bmiColors
[0].rgbRed
== 0xff
1210 && bi
->bmiColors
[0].rgbGreen
== 0xff
1211 && bi
->bmiColors
[0].rgbBlue
== 0xff
1212 && bi
->bmiColors
[0].rgbReserved
== 0
1213 && bi
->bmiColors
[1].rgbRed
== 0
1214 && bi
->bmiColors
[1].rgbGreen
== 0
1215 && bi
->bmiColors
[1].rgbBlue
== 0
1216 && bi
->bmiColors
[1].rgbReserved
== 0)
1218 (bi
->bmiColors
[0].rgbRed
== 0
1219 && bi
->bmiColors
[0].rgbGreen
== 0
1220 && bi
->bmiColors
[0].rgbBlue
== 0
1221 && bi
->bmiColors
[0].rgbReserved
== 0
1222 && bi
->bmiColors
[1].rgbRed
== 0xff
1223 && bi
->bmiColors
[1].rgbGreen
== 0xff
1224 && bi
->bmiColors
[1].rgbBlue
== 0xff
1225 && bi
->bmiColors
[1].rgbReserved
== 0);
1228 else if (!monochrome
)
1230 monochrome
= ds
.dsBm
.bmBitsPixel
== 1;
1235 res
= CreateBitmap(desiredx
, desiredy
, 1, 1, NULL
);
1239 HDC screenDC
= GetDC(NULL
);
1240 res
= CreateCompatibleBitmap(screenDC
, desiredx
, desiredy
);
1241 ReleaseDC(NULL
, screenDC
);
1247 /* Only copy the bitmap if it's a DIB section or if it's
1248 compatible to the screen */
1251 if (objSize
== sizeof(DIBSECTION
))
1253 copyContents
= TRUE
;
1257 HDC screenDC
= GetDC(NULL
);
1258 int screen_depth
= GetDeviceCaps(screenDC
, BITSPIXEL
);
1259 ReleaseDC(NULL
, screenDC
);
1261 copyContents
= (ds
.dsBm
.bmBitsPixel
== 1 || ds
.dsBm
.bmBitsPixel
== screen_depth
);
1266 /* The source bitmap may already be selected in a device context,
1267 use GetDIBits/StretchDIBits and not StretchBlt */
1272 dc
= CreateCompatibleDC(NULL
);
1274 bi
->bmiHeader
.biWidth
= ds
.dsBm
.bmWidth
;
1275 bi
->bmiHeader
.biHeight
= ds
.dsBm
.bmHeight
;
1276 bi
->bmiHeader
.biSizeImage
= 0;
1277 bi
->bmiHeader
.biClrUsed
= 0;
1278 bi
->bmiHeader
.biClrImportant
= 0;
1280 /* Fill in biSizeImage */
1281 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
1282 bits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, bi
->bmiHeader
.biSizeImage
);
1288 /* Get the image bits of the source bitmap */
1289 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, bits
, bi
, DIB_RGB_COLORS
);
1291 /* Copy it to the destination bitmap */
1292 oldBmp
= SelectObject(dc
, res
);
1293 StretchDIBits(dc
, 0, 0, desiredx
, desiredy
,
1294 0, 0, ds
.dsBm
.bmWidth
, ds
.dsBm
.bmHeight
,
1295 bits
, bi
, DIB_RGB_COLORS
, SRCCOPY
);
1296 SelectObject(dc
, oldBmp
);
1298 HeapFree(GetProcessHeap(), 0, bits
);
1304 if (flags
& LR_COPYDELETEORG
)
1309 HeapFree(GetProcessHeap(), 0, bi
);
1315 CURSORICON_CopyImage(
1326 if(fuFlags
& LR_COPYFROMRESOURCE
)
1328 /* Get the icon module/resource names */
1329 UNICODE_STRING ustrModule
;
1330 UNICODE_STRING ustrRsrc
;
1334 ustrModule
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
1335 ustrRsrc
.MaximumLength
= 256;
1337 ustrModule
.Buffer
= HeapAlloc(GetProcessHeap(), 0, ustrModule
.MaximumLength
);
1338 if(!ustrModule
.Buffer
)
1340 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1343 /* Keep track of the buffer for the resource, NtUserGetIconInfo might overwrite it */
1344 pvBuf
= HeapAlloc(GetProcessHeap(), 0, ustrRsrc
.MaximumLength
);
1347 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1348 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1351 ustrRsrc
.Buffer
= pvBuf
;
1355 if(!NtUserGetIconInfo(hicon
, NULL
, &ustrModule
, &ustrRsrc
, NULL
, FALSE
))
1357 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1358 HeapFree(GetProcessHeap(), 0, pvBuf
);
1362 if((ustrModule
.Length
< ustrModule
.MaximumLength
) && (ustrRsrc
.Length
< ustrRsrc
.MaximumLength
))
1364 /* Buffers were big enough */
1368 /* Find which buffer were too small */
1369 if(ustrModule
.Length
== ustrModule
.MaximumLength
)
1372 ustrModule
.MaximumLength
*= 2;
1373 newBuffer
= HeapReAlloc(GetProcessHeap(), 0, ustrModule
.Buffer
, ustrModule
.MaximumLength
);
1374 if(!ustrModule
.Buffer
)
1376 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1379 ustrModule
.Buffer
= newBuffer
;
1382 if(ustrRsrc
.Length
== ustrRsrc
.MaximumLength
)
1384 ustrRsrc
.MaximumLength
*= 2;
1385 pvBuf
= HeapReAlloc(GetProcessHeap(), 0, ustrRsrc
.Buffer
, ustrRsrc
.MaximumLength
);
1388 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1391 ustrRsrc
.Buffer
= pvBuf
;
1395 /* NULL-terminate our strings */
1396 ustrModule
.Buffer
[ustrModule
.Length
/sizeof(WCHAR
)] = 0;
1397 if(!IS_INTRESOURCE(ustrRsrc
.Buffer
))
1398 ustrRsrc
.Buffer
[ustrRsrc
.Length
/sizeof(WCHAR
)] = 0;
1400 /* Get the module handle */
1401 if(!GetModuleHandleExW(0, ustrModule
.Buffer
, &hModule
))
1403 /* This hould never happen */
1404 ERR("Invalid handle?.\n");
1405 SetLastError(ERROR_INVALID_PARAMETER
);
1409 /* Call the relevant function */
1410 ret
= CURSORICON_LoadImageW(hModule
, ustrRsrc
.Buffer
, cxDesired
, cyDesired
, fuFlags
& LR_DEFAULTSIZE
, bIcon
);
1412 FreeLibrary(hModule
);
1414 /* If we're here, that means that the passed icon is shared. Don't destroy it, even if LR_COPYDELETEORG is specified */
1416 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1417 HeapFree(GetProcessHeap(), 0, pvBuf
);
1419 TRACE("Returning 0x%08x.\n", ret
);
1424 /* This is a regular copy */
1425 if(fuFlags
& ~LR_COPYDELETEORG
)
1426 FIXME("Unimplemented flags: 0x%08x\n", fuFlags
);
1428 if(!GetIconInfo(hicon
, &ii
))
1430 ERR("GetIconInfo failed.\n");
1434 ret
= CreateIconIndirect(&ii
);
1436 DeleteObject(ii
.hbmMask
);
1437 if(ii
.hbmColor
) DeleteObject(ii
.hbmColor
);
1439 if(ret
&& (fuFlags
& LR_COPYDELETEORG
))
1445 /************* PUBLIC FUNCTIONS *******************/
1447 HANDLE WINAPI
CopyImage(
1455 TRACE("hImage=%p, uType=%u, cxDesired=%d, cyDesired=%d, fuFlags=%x\n",
1456 hImage
, uType
, cxDesired
, cyDesired
, fuFlags
);
1460 return BITMAP_CopyImage(hImage
, cxDesired
, cyDesired
, fuFlags
);
1463 return CURSORICON_CopyImage(hImage
, uType
== IMAGE_ICON
, cxDesired
, cyDesired
, fuFlags
);
1465 SetLastError(ERROR_INVALID_PARAMETER
);
1471 HICON WINAPI
CopyIcon(
1479 BOOL WINAPI
DrawIcon(
1486 return DrawIconEx(hDC
, X
, Y
, hIcon
, 0, 0, 0, NULL
, DI_NORMAL
| DI_COMPAT
| DI_DEFAULTSIZE
);
1489 BOOL WINAPI
DrawIconEx(
1496 _In_ UINT istepIfAniCur
,
1497 _In_opt_ HBRUSH hbrFlickerFreeDraw
,
1501 return NtUserDrawIconEx(hdc
, xLeft
, yTop
, hIcon
, cxWidth
, cyWidth
,
1502 istepIfAniCur
, hbrFlickerFreeDraw
, diFlags
,
1506 BOOL WINAPI
GetIconInfo(
1508 _Out_ PICONINFO piconinfo
1511 return NtUserGetIconInfo(hIcon
, piconinfo
, NULL
, NULL
, NULL
, FALSE
);
1514 BOOL WINAPI
DestroyIcon(
1518 return NtUserDestroyCursor(hIcon
, FALSE
);
1521 HICON WINAPI
LoadIconA(
1522 _In_opt_ HINSTANCE hInstance
,
1523 _In_ LPCSTR lpIconName
1526 TRACE("%p, %s\n", hInstance
, debugstr_a(lpIconName
));
1528 return LoadImageA(hInstance
,
1533 LR_SHARED
| LR_DEFAULTSIZE
);
1536 HICON WINAPI
LoadIconW(
1537 _In_opt_ HINSTANCE hInstance
,
1538 _In_ LPCWSTR lpIconName
1541 TRACE("%p, %s\n", hInstance
, debugstr_w(lpIconName
));
1543 return LoadImageW(hInstance
,
1548 LR_SHARED
| LR_DEFAULTSIZE
);
1551 HCURSOR WINAPI
LoadCursorA(
1552 _In_opt_ HINSTANCE hInstance
,
1553 _In_ LPCSTR lpCursorName
1556 TRACE("%p, %s\n", hInstance
, debugstr_a(lpCursorName
));
1558 return LoadImageA(hInstance
,
1563 LR_SHARED
| LR_DEFAULTSIZE
);
1566 HCURSOR WINAPI
LoadCursorW(
1567 _In_opt_ HINSTANCE hInstance
,
1568 _In_ LPCWSTR lpCursorName
1571 TRACE("%p, %s\n", hInstance
, debugstr_w(lpCursorName
));
1573 return LoadImageW(hInstance
,
1578 LR_SHARED
| LR_DEFAULTSIZE
);
1581 HCURSOR WINAPI
LoadCursorFromFileA(
1582 _In_ LPCSTR lpFileName
1585 TRACE("%s\n", debugstr_a(lpFileName
));
1587 return LoadImageA(NULL
,
1592 LR_LOADFROMFILE
| LR_DEFAULTSIZE
);
1595 HCURSOR WINAPI
LoadCursorFromFileW(
1596 _In_ LPCWSTR lpFileName
1599 TRACE("%s\n", debugstr_w(lpFileName
));
1601 return LoadImageW(NULL
,
1606 LR_LOADFROMFILE
| LR_DEFAULTSIZE
);
1609 HBITMAP WINAPI
LoadBitmapA(
1610 _In_opt_ HINSTANCE hInstance
,
1611 _In_ LPCSTR lpBitmapName
1614 TRACE("%p, %s\n", hInstance
, debugstr_a(lpBitmapName
));
1616 return LoadImageA(hInstance
,
1624 HBITMAP WINAPI
LoadBitmapW(
1625 _In_opt_ HINSTANCE hInstance
,
1626 _In_ LPCWSTR lpBitmapName
1629 TRACE("%p, %s\n", hInstance
, debugstr_w(lpBitmapName
));
1631 return LoadImageW(hInstance
,
1639 HANDLE WINAPI
LoadImageA(
1640 _In_opt_ HINSTANCE hinst
,
1641 _In_ LPCSTR lpszName
,
1652 if (IS_INTRESOURCE(lpszName
))
1653 return LoadImageW(hinst
, (LPCWSTR
)lpszName
, uType
, cxDesired
, cyDesired
, fuLoad
);
1655 len
= MultiByteToWideChar( CP_ACP
, 0, lpszName
, -1, NULL
, 0 );
1656 u_name
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
1657 MultiByteToWideChar( CP_ACP
, 0, lpszName
, -1, u_name
, len
);
1659 res
= LoadImageW(hinst
, u_name
, uType
, cxDesired
, cyDesired
, fuLoad
);
1660 HeapFree(GetProcessHeap(), 0, u_name
);
1664 HANDLE WINAPI
LoadImageW(
1665 _In_opt_ HINSTANCE hinst
,
1666 _In_ LPCWSTR lpszName
,
1673 /* Redirect to each implementation */
1677 return BITMAP_LoadImageW(hinst
, lpszName
, cxDesired
, cyDesired
, fuLoad
);
1680 return CURSORICON_LoadImageW(hinst
, lpszName
, cxDesired
, cyDesired
, fuLoad
, uType
== IMAGE_ICON
);
1682 SetLastError(ERROR_INVALID_PARAMETER
);
1688 int WINAPI
LookupIconIdFromDirectory(
1689 _In_ PBYTE presbits
,
1693 return LookupIconIdFromDirectoryEx( presbits
, fIcon
,
1694 fIcon
? GetSystemMetrics(SM_CXICON
) : GetSystemMetrics(SM_CXCURSOR
),
1695 fIcon
? GetSystemMetrics(SM_CYICON
) : GetSystemMetrics(SM_CYCURSOR
), fIcon
? 0 : LR_MONOCHROME
);
1698 int WINAPI
LookupIconIdFromDirectoryEx(
1699 _In_ PBYTE presbits
,
1707 CURSORICONDIR
* dir
= (CURSORICONDIR
*)presbits
;
1708 CURSORICONDIRENTRY
* entry
;
1709 int i
, numMatch
, iIndex
= -1;
1712 ULONG cxyDiff
, cxyDiffTmp
;
1714 TRACE("%p, %x, %i, %i, %x.\n", presbits
, fIcon
, cxDesired
, cyDesired
, Flags
);
1716 if(!(dir
&& !dir
->idReserved
&& (dir
->idType
& 3)))
1718 WARN("Invalid resource.\n");
1722 if(Flags
& LR_MONOCHROME
)
1727 icScreen
= CreateICW(DISPLAYW
, NULL
, NULL
, NULL
);
1731 bppDesired
= GetDeviceCaps(icScreen
, BITSPIXEL
);
1736 cxDesired
= GetSystemMetrics(fIcon
? SM_CXICON
: SM_CXCURSOR
);
1738 cyDesired
= GetSystemMetrics(fIcon
? SM_CYICON
: SM_CYCURSOR
);
1740 /* Find the best match for the desired size */
1741 cxyDiff
= 0xFFFFFFFF;
1743 for(i
= 0; i
< dir
->idCount
; i
++)
1745 entry
= &dir
->idEntries
[i
];
1746 width
= fIcon
? entry
->ResInfo
.icon
.bWidth
: entry
->ResInfo
.cursor
.wWidth
;
1747 /* Height is twice as big in cursor resources */
1748 height
= fIcon
? entry
->ResInfo
.icon
.bHeight
: entry
->ResInfo
.cursor
.wHeight
/2;
1749 /* 0 represents 256 */
1750 if(!width
) width
= 256;
1751 if(!height
) height
= 256;
1752 /* Let it be a 1-norm */
1753 cxyDiffTmp
= max(abs(width
- cxDesired
), abs(height
- cyDesired
));
1754 if( cxyDiffTmp
> cxyDiff
)
1756 if( cxyDiffTmp
== cxyDiff
)
1763 cxyDiff
= cxyDiffTmp
;
1768 /* Only one entry fit the asked dimensions */
1769 return dir
->idEntries
[iIndex
].wResId
;
1774 /* Now find the entry with the best depth */
1775 for(i
= 0; i
< dir
->idCount
; i
++)
1777 entry
= &dir
->idEntries
[i
];
1778 width
= fIcon
? entry
->ResInfo
.icon
.bWidth
: entry
->ResInfo
.cursor
.wWidth
;
1779 height
= fIcon
? entry
->ResInfo
.icon
.bHeight
: entry
->ResInfo
.cursor
.wHeight
/2;
1780 /* 0 represents 256 */
1781 if(!width
) width
= 256;
1782 if(!height
) height
= 256;
1783 /* Check if this is the best match we had */
1784 cxyDiffTmp
= max(abs(width
- cxDesired
), abs(height
- cyDesired
));
1785 if(cxyDiffTmp
!= cxyDiff
)
1788 if(entry
->wBitCount
== bppDesired
)
1789 return entry
->wResId
;
1790 /* We take the highest possible but smaller than the display depth */
1791 if((entry
->wBitCount
> bitcount
) && (entry
->wBitCount
< bppDesired
))
1794 bitcount
= entry
->wBitCount
;
1799 return dir
->idEntries
[iIndex
].wResId
;
1801 /* No inferior or equal depth available. Get the smallest one */
1803 for(i
= 0; i
< dir
->idCount
; i
++)
1805 entry
= &dir
->idEntries
[i
];
1806 width
= fIcon
? entry
->ResInfo
.icon
.bWidth
: entry
->ResInfo
.cursor
.wWidth
;
1807 height
= fIcon
? entry
->ResInfo
.icon
.bHeight
: entry
->ResInfo
.cursor
.wHeight
/2;
1808 /* 0 represents 256 */
1809 if(!width
) width
= 256;
1810 if(!height
) height
= 256;
1811 /* Check if this is the best match we had */
1812 cxyDiffTmp
= max(abs(width
- cxDesired
), abs(height
- cyDesired
));
1813 if(cxyDiffTmp
!= cxyDiff
)
1815 /* Check the bit depth */
1816 if(entry
->wBitCount
< bitcount
)
1819 bitcount
= entry
->wBitCount
;
1823 return dir
->idEntries
[iIndex
].wResId
;
1826 HICON WINAPI
CreateIcon(
1827 _In_opt_ HINSTANCE hInstance
,
1831 _In_ BYTE cBitsPixel
,
1832 _In_
const BYTE
*lpbANDbits
,
1833 _In_
const BYTE
*lpbXORbits
1839 TRACE_(icon
)("%dx%d, planes %d, bpp %d, xor %p, and %p\n",
1840 nWidth
, nHeight
, cPlanes
, cBitsPixel
, lpbXORbits
, lpbANDbits
);
1843 iinfo
.xHotspot
= nWidth
/ 2;
1844 iinfo
.yHotspot
= nHeight
/ 2;
1845 if (cPlanes
* cBitsPixel
> 1)
1847 iinfo
.hbmColor
= CreateBitmap( nWidth
, nHeight
, cPlanes
, cBitsPixel
, lpbXORbits
);
1848 iinfo
.hbmMask
= CreateBitmap( nWidth
, nHeight
, 1, 1, lpbANDbits
);
1852 iinfo
.hbmMask
= CreateBitmap( nWidth
, nHeight
* 2, 1, 1, lpbANDbits
);
1853 iinfo
.hbmColor
= NULL
;
1856 hIcon
= CreateIconIndirect( &iinfo
);
1858 DeleteObject( iinfo
.hbmMask
);
1859 if (iinfo
.hbmColor
) DeleteObject( iinfo
.hbmColor
);
1864 HICON WINAPI
CreateIconFromResource(
1865 _In_ PBYTE presbits
,
1866 _In_ DWORD dwResSize
,
1871 return CreateIconFromResourceEx( presbits
, dwResSize
, fIcon
, dwVer
, 0, 0, LR_DEFAULTSIZE
| LR_SHARED
);
1874 HICON WINAPI
CreateIconFromResourceEx(
1875 _In_ PBYTE pbIconBits
,
1876 _In_ DWORD cbIconBits
,
1878 _In_ DWORD dwVersion
,
1884 CURSORDATA cursorData
;
1887 TRACE("%p, %lu, %lu, %lu, %i, %i, %lu.\n", pbIconBits
, cbIconBits
, fIcon
, dwVersion
, cxDesired
, cyDesired
, uFlags
);
1889 if(uFlags
& ~LR_DEFAULTSIZE
)
1890 FIXME("uFlags 0x%08x ignored.\n", uFlags
& ~LR_DEFAULTSIZE
);
1892 if(uFlags
& LR_DEFAULTSIZE
)
1894 if(!cxDesired
) cxDesired
= GetSystemMetrics(fIcon
? SM_CXICON
: SM_CXCURSOR
);
1895 if(!cyDesired
) cyDesired
= GetSystemMetrics(fIcon
? SM_CYICON
: SM_CYCURSOR
);
1898 /* Check if this is an animated cursor */
1899 if(!memcmp(pbIconBits
, "RIFF", 4))
1905 ZeroMemory(&cursorData
, sizeof(cursorData
));
1906 cursorData
.cx
= cxDesired
;
1907 cursorData
.cy
= cyDesired
;
1908 cursorData
.rt
= (USHORT
)((ULONG_PTR
)(fIcon
? RT_ICON
: RT_CURSOR
));
1911 WORD
* pt
= (WORD
*)pbIconBits
;
1912 cursorData
.xHotspot
= *pt
++;
1913 cursorData
.yHotspot
= *pt
++;
1914 pbIconBits
= (PBYTE
)pt
;
1917 if(!CURSORICON_GetCursorDataFromBMI(&cursorData
, (BITMAPINFO
*)pbIconBits
))
1919 ERR("Couldn't fill the CURSORDATA structure.\n");
1923 hIcon
= NtUserxCreateEmptyCurObject(fIcon
? 0 : 1);
1927 if(!NtUserSetCursorIconData(hIcon
, NULL
, NULL
, &cursorData
))
1929 ERR("NtUserSetCursorIconData failed.\n");
1930 NtUserDestroyCursor(hIcon
, TRUE
);
1938 DeleteObject(cursorData
.hbmMask
);
1939 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
1940 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
1945 HICON WINAPI
CreateIconIndirect(
1946 _In_ PICONINFO piconinfo
1949 /* As simple as creating a handle, and let win32k deal with the bitmaps */
1951 CURSORDATA cursorData
;
1953 TRACE("%p.\n", piconinfo
);
1955 if(!CURSORICON_GetCursorDataFromIconInfo(&cursorData
, piconinfo
))
1958 hiconRet
= NtUserxCreateEmptyCurObject(piconinfo
->fIcon
? 0 : 1);
1962 if(!NtUserSetCursorIconData(hiconRet
, NULL
, NULL
, &cursorData
))
1964 NtUserDestroyCursor(hiconRet
, FALSE
);
1968 TRACE("Returning 0x%08x.\n", hiconRet
);
1974 DeleteObject(cursorData
.hbmMask
);
1975 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
1976 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
1981 HCURSOR WINAPI
CreateCursor(
1982 _In_opt_ HINSTANCE hInst
,
1987 _In_
const VOID
*pvANDPlane
,
1988 _In_
const VOID
*pvXORPlane
1994 TRACE_(cursor
)("%dx%d spot=%d,%d xor=%p and=%p\n",
1995 nWidth
, nHeight
, xHotSpot
, yHotSpot
, pvXORPlane
, pvANDPlane
);
1998 info
.xHotspot
= xHotSpot
;
1999 info
.yHotspot
= yHotSpot
;
2000 info
.hbmMask
= CreateBitmap( nWidth
, nHeight
, 1, 1, pvANDPlane
);
2001 info
.hbmColor
= CreateBitmap( nWidth
, nHeight
, 1, 1, pvXORPlane
);
2002 hCursor
= CreateIconIndirect( &info
);
2003 DeleteObject( info
.hbmMask
);
2004 DeleteObject( info
.hbmColor
);
2008 BOOL WINAPI
SetSystemCursor(
2017 BOOL WINAPI
SetCursorPos(
2022 return NtUserxSetCursorPos(X
,Y
);
2025 BOOL WINAPI
GetCursorPos(
2026 _Out_ LPPOINT lpPoint
2029 return NtUserxGetCursorPos(lpPoint
);
2032 int WINAPI
ShowCursor(
2036 return NtUserxShowCursor(bShow
);
2039 HCURSOR WINAPI
GetCursor(void)
2041 return (HCURSOR
)NtUserGetThreadState(THREADSTATE_GETCURSOR
);
2044 BOOL WINAPI
DestroyCursor(
2045 _In_ HCURSOR hCursor
2048 return NtUserDestroyCursor(hCursor
, FALSE
);