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 /* We only use Wide string functions */
18 #undef MAKEINTRESOURCE
19 #define MAKEINTRESOURCE MAKEINTRESOURCEW
21 /************* USER32 INTERNAL FUNCTIONS **********/
23 /* This callback routine is called directly after switching to gui mode */
26 User32SetupDefaultCursors(PVOID Arguments
,
29 BOOL
*DefaultCursor
= (BOOL
*)Arguments
;
34 /* set default cursor */
35 hCursor
= LoadCursorW(0, IDC_ARROW
);
40 /* FIXME load system cursor scheme */
42 hCursor
= LoadCursorW(0, IDC_ARROW
);
46 return(ZwCallbackReturn(&hCursor
, sizeof(HCURSOR
), STATUS_SUCCESS
));
49 BOOL
get_icon_size(HICON hIcon
, SIZE
*size
)
51 return NtUserGetIconSize(hIcon
, 0, &size
->cx
, &size
->cy
);
54 HCURSOR
CursorIconToCursor(HICON hIcon
, BOOL SemiTransparent
)
60 /************* IMPLEMENTATION HELPERS ******************/
62 static const WCHAR DISPLAYW
[] = L
"DISPLAY";
64 static void *map_fileW( LPCWSTR name
, LPDWORD filesize
)
66 HANDLE hFile
, hMapping
;
69 hFile
= CreateFileW( name
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
70 OPEN_EXISTING
, FILE_FLAG_RANDOM_ACCESS
, 0 );
71 if (hFile
!= INVALID_HANDLE_VALUE
)
73 hMapping
= CreateFileMappingW( hFile
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
76 ptr
= MapViewOfFile( hMapping
, FILE_MAP_READ
, 0, 0, 0 );
77 CloseHandle( hMapping
);
79 *filesize
= GetFileSize( hFile
, NULL
);
86 static int get_dib_image_size( int width
, int height
, int depth
)
88 return (((width
* depth
+ 31) / 8) & ~3) * abs( height
);
91 static BOOL
is_dib_monochrome( const BITMAPINFO
* info
)
93 if (info
->bmiHeader
.biBitCount
!= 1) return FALSE
;
95 if (info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
97 const RGBTRIPLE
*rgb
= ((const BITMAPCOREINFO
*)info
)->bmciColors
;
99 /* Check if the first color is black */
100 if ((rgb
->rgbtRed
== 0) && (rgb
->rgbtGreen
== 0) && (rgb
->rgbtBlue
== 0))
104 /* Check if the second color is white */
105 return ((rgb
->rgbtRed
== 0xff) && (rgb
->rgbtGreen
== 0xff)
106 && (rgb
->rgbtBlue
== 0xff));
110 else /* assume BITMAPINFOHEADER */
112 const RGBQUAD
*rgb
= info
->bmiColors
;
114 /* Check if the first color is black */
115 if ((rgb
->rgbRed
== 0) && (rgb
->rgbGreen
== 0) &&
116 (rgb
->rgbBlue
== 0) && (rgb
->rgbReserved
== 0))
120 /* Check if the second color is white */
121 return ((rgb
->rgbRed
== 0xff) && (rgb
->rgbGreen
== 0xff)
122 && (rgb
->rgbBlue
== 0xff) && (rgb
->rgbReserved
== 0));
128 static int bitmap_info_size( const BITMAPINFO
* info
, WORD coloruse
)
130 unsigned int colors
, size
, masks
= 0;
132 if (info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
134 const BITMAPCOREHEADER
*core
= (const BITMAPCOREHEADER
*)info
;
135 colors
= (core
->bcBitCount
<= 8) ? 1 << core
->bcBitCount
: 0;
136 return sizeof(BITMAPCOREHEADER
) + colors
*
137 ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBTRIPLE
) : sizeof(WORD
));
139 else /* assume BITMAPINFOHEADER */
141 colors
= info
->bmiHeader
.biClrUsed
;
142 if (colors
> 256) /* buffer overflow otherwise */
144 if (!colors
&& (info
->bmiHeader
.biBitCount
<= 8))
145 colors
= 1 << info
->bmiHeader
.biBitCount
;
146 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
) masks
= 3;
147 size
= max( info
->bmiHeader
.biSize
, sizeof(BITMAPINFOHEADER
) + masks
* sizeof(DWORD
) );
148 return size
+ colors
* ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBQUAD
) : sizeof(WORD
));
152 static int DIB_GetBitmapInfo( const BITMAPINFOHEADER
*header
, LONG
*width
,
153 LONG
*height
, WORD
*bpp
, DWORD
*compr
)
155 if (header
->biSize
== sizeof(BITMAPCOREHEADER
))
157 const BITMAPCOREHEADER
*core
= (const BITMAPCOREHEADER
*)header
;
158 *width
= core
->bcWidth
;
159 *height
= core
->bcHeight
;
160 *bpp
= core
->bcBitCount
;
164 else if (header
->biSize
== sizeof(BITMAPINFOHEADER
) ||
165 header
->biSize
== sizeof(BITMAPV4HEADER
) ||
166 header
->biSize
== sizeof(BITMAPV5HEADER
))
168 *width
= header
->biWidth
;
169 *height
= header
->biHeight
;
170 *bpp
= header
->biBitCount
;
171 *compr
= header
->biCompression
;
174 ERR("(%d): unknown/wrong size for header\n", header
->biSize
);
178 /* copy an icon bitmap, even when it can't be selected into a DC */
179 /* helper for CreateIconIndirect */
180 static void stretch_blt_icon(HDC hdc_dst
, int dst_width
, int dst_height
, HBITMAP src
)
182 HDC hdc
= CreateCompatibleDC( 0 );
186 GetObjectW(src
, sizeof(bm
), &bm
);
188 hbmpPrev
= SelectObject(hdc
, src
);
190 if (!hbmpPrev
) /* do it the hard way */
195 if (!(info
= HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )))) return;
196 info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
197 info
->bmiHeader
.biWidth
= bm
.bmWidth
;
198 info
->bmiHeader
.biHeight
= bm
.bmHeight
;
199 info
->bmiHeader
.biPlanes
= GetDeviceCaps( hdc_dst
, PLANES
);
200 info
->bmiHeader
.biBitCount
= GetDeviceCaps( hdc_dst
, BITSPIXEL
);
201 info
->bmiHeader
.biCompression
= BI_RGB
;
202 info
->bmiHeader
.biSizeImage
= get_dib_image_size( bm
.bmWidth
, bm
.bmHeight
, info
->bmiHeader
.biBitCount
);
203 info
->bmiHeader
.biXPelsPerMeter
= 0;
204 info
->bmiHeader
.biYPelsPerMeter
= 0;
205 info
->bmiHeader
.biClrUsed
= 0;
206 info
->bmiHeader
.biClrImportant
= 0;
207 bits
= HeapAlloc( GetProcessHeap(), 0, info
->bmiHeader
.biSizeImage
);
208 if (bits
&& GetDIBits( hdc
, src
, 0, bm
.bmHeight
, bits
, info
, DIB_RGB_COLORS
))
209 StretchDIBits( hdc_dst
, 0, 0, dst_width
, dst_height
,
210 0, 0, bm
.bmWidth
, bm
.bmHeight
, bits
, info
, DIB_RGB_COLORS
, SRCCOPY
);
212 HeapFree( GetProcessHeap(), 0, bits
);
213 HeapFree( GetProcessHeap(), 0, info
);
217 StretchBlt( hdc_dst
, 0, 0, dst_width
, dst_height
, hdc
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, SRCCOPY
);
218 SelectObject(hdc
, hbmpPrev
);
224 /***********************************************************************
227 static BOOL
bmi_has_alpha( const BITMAPINFO
*info
, const void *bits
)
230 BOOL has_alpha
= FALSE
;
231 const unsigned char *ptr
= bits
;
233 if (info
->bmiHeader
.biBitCount
!= 32) return FALSE
;
234 for (i
= 0; i
< info
->bmiHeader
.biWidth
* abs(info
->bmiHeader
.biHeight
); i
++, ptr
+= 4)
235 if ((has_alpha
= (ptr
[3] != 0))) break;
239 /***********************************************************************
240 * create_alpha_bitmap
242 * Create the alpha bitmap for a 32-bpp icon that has an alpha channel.
244 static HBITMAP
create_alpha_bitmap(
246 _In_opt_
const BITMAPINFO
*src_info
,
247 _In_opt_
const void *color_bits
)
249 HBITMAP alpha
= NULL
, hbmpOld
;
250 BITMAPINFO
*info
= NULL
;
251 HDC hdc
= NULL
, hdcScreen
;
258 if (!GetObjectW( color
, sizeof(bm
), &bm
))
260 if (bm
.bmBitsPixel
!= 32)
263 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
266 if(GetDeviceCaps(hdcScreen
, BITSPIXEL
) != 32)
268 hdc
= CreateCompatibleDC(hdcScreen
);
278 if(!bmi_has_alpha(src_info
, color_bits
))
281 if(!DIB_GetBitmapInfo(&src_info
->bmiHeader
, &width
, &height
, &bpp
, &compr
))
286 size
= get_dib_image_size(width
, height
, bpp
);
287 bits
= HeapAlloc(GetProcessHeap(), 0, size
);
290 CopyMemory(bits
, color_bits
, size
);
294 info
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(BITMAPINFO
, bmiColors
[256]));
297 info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
298 info
->bmiHeader
.biWidth
= bm
.bmWidth
;
299 info
->bmiHeader
.biHeight
= -bm
.bmHeight
;
300 info
->bmiHeader
.biPlanes
= 1;
301 info
->bmiHeader
.biBitCount
= 32;
302 info
->bmiHeader
.biCompression
= BI_RGB
;
303 info
->bmiHeader
.biSizeImage
= bm
.bmWidth
* bm
.bmHeight
* 4;
304 info
->bmiHeader
.biXPelsPerMeter
= 0;
305 info
->bmiHeader
.biYPelsPerMeter
= 0;
306 info
->bmiHeader
.biClrUsed
= 0;
307 info
->bmiHeader
.biClrImportant
= 0;
309 bits
= HeapAlloc(GetProcessHeap(), 0, info
->bmiHeader
.biSizeImage
);
312 if(!GetDIBits( hdc
, color
, 0, bm
.bmHeight
, bits
, info
, DIB_RGB_COLORS
))
314 if (!bmi_has_alpha( info
, bits
))
317 height
= bm
.bmHeight
;
320 /* pre-multiply by alpha */
321 for (i
= 0, ptr
= bits
; i
< width
* height
; i
++, ptr
+= 4)
323 unsigned int alpha
= ptr
[3];
324 ptr
[0] = ptr
[0] * alpha
/ 255;
325 ptr
[1] = ptr
[1] * alpha
/ 255;
326 ptr
[2] = ptr
[2] * alpha
/ 255;
329 /* Create the bitmap */
330 alpha
= CreateCompatibleBitmap(hdcScreen
, bm
.bmWidth
, bm
.bmHeight
);
333 hbmpOld
= SelectObject(hdc
, alpha
);
336 if(!StretchDIBits( hdc
, 0, 0, bm
.bmWidth
, bm
.bmHeight
,
338 bits
, src_info
? src_info
: info
, DIB_RGB_COLORS
, SRCCOPY
))
340 SelectObject(hdc
, hbmpOld
);
345 SelectObject(hdc
, hbmpOld
);
349 if(hdc
) DeleteDC( hdc
);
350 if(info
) HeapFree( GetProcessHeap(), 0, info
);
351 if(bits
) HeapFree(GetProcessHeap(), 0, bits
);
353 TRACE("Returning 0x%08x.\n", alpha
);
357 #include "pshpack1.h"
368 } CURSORICONFILEDIRENTRY
;
375 CURSORICONFILEDIRENTRY idEntries
[1];
381 const CURSORICONFILEDIRENTRY
*
382 get_best_icon_file_entry(
383 _In_
const CURSORICONFILEDIR
* dir
,
384 _In_ DWORD dwFileSize
,
391 CURSORICONDIR
* fakeDir
;
392 CURSORICONDIRENTRY
* fakeEntry
;
394 const CURSORICONFILEDIRENTRY
* entry
;
396 /* Check our file is what it claims to be */
397 if ( dwFileSize
< sizeof(*dir
) )
400 if (dwFileSize
< (sizeof(*dir
) + FIELD_OFFSET(CURSORICONFILEDIR
, idEntries
[dir
->idCount
])))
405 * We allocate a buffer, fake it as if it was a pointer to a resource in a module,
406 * pass it to LookupIconIdFromDirectoryEx and get back the index we have to use
408 fakeDir
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(CURSORICONDIR
, idEntries
[dir
->idCount
]));
411 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
414 fakeDir
->idReserved
= 0;
415 fakeDir
->idType
= dir
->idType
;
416 fakeDir
->idCount
= dir
->idCount
;
417 for(i
= 0; i
<dir
->idCount
; i
++)
419 fakeEntry
= &fakeDir
->idEntries
[i
];
420 entry
= &dir
->idEntries
[i
];
421 /* Take this as an occasion to perform a size check */
422 if ((entry
->dwDIBOffset
> dwFileSize
)
423 || ((entry
->dwDIBOffset
+ entry
->dwDIBSize
) > dwFileSize
))
425 ERR("Corrupted icon file?.\n");
426 HeapFree(GetProcessHeap(), 0, fakeDir
);
429 /* File icon/cursors are not like resource ones */
432 fakeEntry
->ResInfo
.icon
.bWidth
= entry
->bWidth
;
433 fakeEntry
->ResInfo
.icon
.bHeight
= entry
->bHeight
;
434 fakeEntry
->ResInfo
.icon
.bColorCount
= 0;
435 fakeEntry
->ResInfo
.icon
.bReserved
= 0;
439 fakeEntry
->ResInfo
.cursor
.wWidth
= entry
->bWidth
;
440 fakeEntry
->ResInfo
.cursor
.wHeight
= entry
->bHeight
;
442 /* Let's assume there's always one plane */
443 fakeEntry
->wPlanes
= 1;
444 /* We must get the bitcount from the BITMAPINFOHEADER itself */
445 fakeEntry
->wBitCount
= ((BITMAPINFOHEADER
*)((char *)dir
+ entry
->dwDIBOffset
))->biBitCount
;
446 fakeEntry
->dwBytesInRes
= entry
->dwDIBSize
;
447 fakeEntry
->wResId
= i
+ 1;
450 /* Now call LookupIconIdFromResourceEx */
451 i
= LookupIconIdFromDirectoryEx((PBYTE
)fakeDir
, bIcon
, cxDesired
, cyDesired
, fuLoad
& LR_MONOCHROME
);
452 /* We don't need this anymore */
453 HeapFree(GetProcessHeap(), 0, fakeDir
);
456 WARN("Unable to get a fit entry index.\n");
461 return &dir
->idEntries
[i
-1];
466 /************* IMPLEMENTATION CORE ****************/
468 static BOOL
CURSORICON_GetCursorDataFromBMI(
469 _Inout_ CURSORDATA
* pdata
,
470 _In_
const BITMAPINFO
*pbmi
473 UINT ubmiSize
= bitmap_info_size(pbmi
, DIB_RGB_COLORS
);
474 BOOL monochrome
= is_dib_monochrome(pbmi
);
480 BITMAPINFO
* pbmiCopy
;
481 HBITMAP hbmpOld
= NULL
;
482 BOOL bResult
= FALSE
;
483 const VOID
*pvColor
, *pvMask
;
485 ibmpType
= DIB_GetBitmapInfo(&pbmi
->bmiHeader
, &width
, &height
, &bpp
, &compr
);
490 /* No compression for icons */
494 /* If no dimensions were set, use the one from the icon */
495 if(!pdata
->cx
) pdata
->cx
= width
;
496 if(!pdata
->cy
) pdata
->cy
= height
< 0 ? -height
/2 : height
/2;
498 /* Fix the hotspot coords */
499 if(pdata
->rt
== (USHORT
)((ULONG_PTR
)RT_CURSOR
))
501 if(pdata
->cx
!= width
)
502 pdata
->xHotspot
= (pdata
->xHotspot
* pdata
->cx
) / width
;
503 if(pdata
->cy
!= height
/2)
504 pdata
->yHotspot
= (pdata
->yHotspot
* pdata
->cy
* 2) / height
;
508 pdata
->xHotspot
= pdata
->cx
/2;
509 pdata
->yHotspot
= pdata
->cy
/2;
512 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
515 hdc
= CreateCompatibleDC(hdcScreen
);
522 pbmiCopy
= HeapAlloc(GetProcessHeap(), 0, max(ubmiSize
, FIELD_OFFSET(BITMAPINFO
, bmiColors
[3])));
525 RtlCopyMemory(pbmiCopy
, pbmi
, ubmiSize
);
527 /* In an icon/cursor, the BITMAPINFO holds twice the height */
528 if(pbmiCopy
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
529 ((BITMAPCOREHEADER
*)&pbmiCopy
->bmiHeader
)->bcHeight
/= 2;
531 pbmiCopy
->bmiHeader
.biHeight
/= 2;
534 pvColor
= (const char*)pbmi
+ ubmiSize
;
535 pvMask
= (const char*)pvColor
+
536 get_dib_image_size(width
, height
, bpp
);
541 /* Create the 1bpp bitmap which will contain everything */
542 pdata
->hbmColor
= NULL
;
543 pdata
->hbmMask
= CreateBitmap(pdata
->cx
, pdata
->cy
* 2, 1, 1, NULL
);
546 hbmpOld
= SelectObject(hdc
, pdata
->hbmMask
);
550 if(!StretchDIBits(hdc
, 0, pdata
->cy
, pdata
->cx
, pdata
->cy
,
552 pvColor
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
))
558 /* Create the bitmap. It has to be compatible with the screen surface */
559 pdata
->hbmColor
= CreateCompatibleBitmap(hdcScreen
, pdata
->cx
, pdata
->cy
);
562 /* Create the 1bpp mask bitmap */
563 pdata
->hbmMask
= CreateBitmap(pdata
->cx
, pdata
->cy
, 1, 1, NULL
);
566 hbmpOld
= SelectObject(hdc
, pdata
->hbmColor
);
569 if(!StretchDIBits(hdc
, 0, 0, pdata
->cx
, pdata
->cy
,
571 pvColor
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
))
573 pdata
->bpp
= GetDeviceCaps(hdcScreen
, BITSPIXEL
);
575 pdata
->hbmAlpha
= create_alpha_bitmap(pdata
->hbmColor
, pbmiCopy
, pvColor
);
577 /* Now convert the info to monochrome for the mask bits */
578 if (pbmiCopy
->bmiHeader
.biSize
!= sizeof(BITMAPCOREHEADER
))
580 RGBQUAD
*rgb
= pbmiCopy
->bmiColors
;
582 pbmiCopy
->bmiHeader
.biClrUsed
= pbmiCopy
->bmiHeader
.biClrImportant
= 2;
583 rgb
[0].rgbBlue
= rgb
[0].rgbGreen
= rgb
[0].rgbRed
= 0x00;
584 rgb
[1].rgbBlue
= rgb
[1].rgbGreen
= rgb
[1].rgbRed
= 0xff;
585 rgb
[0].rgbReserved
= rgb
[1].rgbReserved
= 0;
586 pbmiCopy
->bmiHeader
.biBitCount
= 1;
590 RGBTRIPLE
*rgb
= (RGBTRIPLE
*)(((BITMAPCOREHEADER
*)pbmiCopy
) + 1);
592 rgb
[0].rgbtBlue
= rgb
[0].rgbtGreen
= rgb
[0].rgbtRed
= 0x00;
593 rgb
[1].rgbtBlue
= rgb
[1].rgbtGreen
= rgb
[1].rgbtRed
= 0xff;
594 ((BITMAPCOREHEADER
*)&pbmiCopy
->bmiHeader
)->bcBitCount
= 1;
597 /* Set the mask bits */
598 if(!SelectObject(hdc
, pdata
->hbmMask
))
600 bResult
= StretchDIBits(hdc
, 0, 0, pdata
->cx
, pdata
->cy
,
602 pvMask
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
) != 0;
606 if(hbmpOld
) SelectObject(hdc
, hbmpOld
);
608 if(pbmiCopy
) HeapFree(GetProcessHeap(), 0, pbmiCopy
);
609 /* Clean up in case of failure */
612 if(pdata
->hbmMask
) DeleteObject(pdata
->hbmMask
);
613 if(pdata
->hbmColor
) DeleteObject(pdata
->hbmColor
);
614 if(pdata
->hbmAlpha
) DeleteObject(pdata
->hbmAlpha
);
619 static BOOL
CURSORICON_GetCursorDataFromIconInfo(
620 _Out_ CURSORDATA
* pCursorData
,
621 _In_ ICONINFO
* pIconInfo
626 ZeroMemory(pCursorData
, sizeof(*pCursorData
));
627 if(pIconInfo
->hbmColor
)
629 /* We must convert the color bitmap to screen format */
630 HDC hdcScreen
, hdcMem
;
633 /* The mask dictates its dimensions */
634 if (!GetObject(pIconInfo
->hbmMask
, sizeof(bm
), &bm
))
636 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
639 hdcMem
= CreateCompatibleDC(hdcScreen
);
645 pCursorData
->hbmColor
= CreateCompatibleBitmap(hdcScreen
, bm
.bmWidth
, bm
.bmHeight
);
647 if (!pCursorData
->hbmColor
)
652 hbmpPrev
= SelectObject(hdcMem
, pCursorData
->hbmColor
);
656 DeleteObject(pCursorData
->hbmColor
);
659 stretch_blt_icon( hdcMem
, bm
.bmWidth
, bm
.bmHeight
, pIconInfo
->hbmColor
);
660 SelectObject(hdcMem
, hbmpPrev
);
663 pCursorData
->hbmMask
= CopyImage(pIconInfo
->hbmMask
, IMAGE_BITMAP
, 0, 0, LR_MONOCHROME
);
664 if(!pCursorData
->hbmMask
)
667 /* Now, fill some information */
668 pCursorData
->rt
= (USHORT
)((ULONG_PTR
)(pIconInfo
->fIcon
? RT_ICON
: RT_CURSOR
));
669 if(pCursorData
->hbmColor
)
671 GetObject(pCursorData
->hbmColor
, sizeof(bm
), &bm
);
672 pCursorData
->bpp
= bm
.bmBitsPixel
;
673 pCursorData
->cx
= bm
.bmWidth
;
674 pCursorData
->cy
= bm
.bmHeight
;
675 if(pCursorData
->bpp
== 32)
676 pCursorData
->hbmAlpha
= create_alpha_bitmap(pCursorData
->hbmColor
, NULL
, NULL
);
680 GetObject(pCursorData
->hbmMask
, sizeof(bm
), &bm
);
681 pCursorData
->bpp
= 1;
682 pCursorData
->cx
= bm
.bmWidth
;
683 pCursorData
->cy
= bm
.bmHeight
/2;
688 pCursorData
->xHotspot
= pCursorData
->cx
/2;
689 pCursorData
->yHotspot
= pCursorData
->cy
/2;
693 pCursorData
->xHotspot
= pIconInfo
->xHotspot
;
694 pCursorData
->yHotspot
= pIconInfo
->yHotspot
;
701 #define RIFF_FOURCC( c0, c1, c2, c3 ) \
702 ( (DWORD)(BYTE)(c0) | ( (DWORD)(BYTE)(c1) << 8 ) | \
703 ( (DWORD)(BYTE)(c2) << 16 ) | ( (DWORD)(BYTE)(c3) << 24 ) )
705 #define ANI_RIFF_ID RIFF_FOURCC('R', 'I', 'F', 'F')
706 #define ANI_LIST_ID RIFF_FOURCC('L', 'I', 'S', 'T')
707 #define ANI_ACON_ID RIFF_FOURCC('A', 'C', 'O', 'N')
708 #define ANI_anih_ID RIFF_FOURCC('a', 'n', 'i', 'h')
709 #define ANI_seq__ID RIFF_FOURCC('s', 'e', 'q', ' ')
710 #define ANI_fram_ID RIFF_FOURCC('f', 'r', 'a', 'm')
711 #define ANI_rate_ID RIFF_FOURCC('r', 'a', 't', 'e')
713 #define ANI_FLAG_ICON 0x1
714 #define ANI_FLAG_SEQUENCE 0x2
716 #include <pshpack1.h>
731 const unsigned char *data
;
735 static void dump_ani_header( const ani_header
*header
)
737 TRACE(" header size: %d\n", header
->header_size
);
738 TRACE(" frames: %d\n", header
->num_frames
);
739 TRACE(" steps: %d\n", header
->num_steps
);
740 TRACE(" width: %d\n", header
->width
);
741 TRACE(" height: %d\n", header
->height
);
742 TRACE(" bpp: %d\n", header
->bpp
);
743 TRACE(" planes: %d\n", header
->num_planes
);
744 TRACE(" display rate: %d\n", header
->display_rate
);
745 TRACE(" flags: 0x%08x\n", header
->flags
);
748 /* Find an animated cursor chunk, given its type and ID */
749 static void riff_find_chunk( DWORD chunk_id
, DWORD chunk_type
, const riff_chunk_t
*parent_chunk
, riff_chunk_t
*chunk
)
751 const unsigned char *ptr
= parent_chunk
->data
;
752 const unsigned char *end
= parent_chunk
->data
+ (parent_chunk
->data_size
- (2 * sizeof(DWORD
)));
754 if (chunk_type
== ANI_LIST_ID
|| chunk_type
== ANI_RIFF_ID
) end
-= sizeof(DWORD
);
758 if ((!chunk_type
&& *(const DWORD
*)ptr
== chunk_id
)
759 || (chunk_type
&& *(const DWORD
*)ptr
== chunk_type
&& *((const DWORD
*)ptr
+ 2) == chunk_id
))
761 ptr
+= sizeof(DWORD
);
762 chunk
->data_size
= (*(const DWORD
*)ptr
+ 1) & ~1;
763 ptr
+= sizeof(DWORD
);
764 if (chunk_type
== ANI_LIST_ID
|| chunk_type
== ANI_RIFF_ID
) ptr
+= sizeof(DWORD
);
770 ptr
+= sizeof(DWORD
);
771 ptr
+= (*(const DWORD
*)ptr
+ 1) & ~1;
772 ptr
+= sizeof(DWORD
);
776 static BOOL
CURSORICON_GetCursorDataFromANI(
777 _Inout_ CURSORDATA
* pCurData
,
778 _In_
const BYTE
*pData
,
779 _In_ DWORD dwDataSize
,
784 const ani_header
*pHeader
;
785 riff_chunk_t root_chunk
= { dwDataSize
, pData
};
786 riff_chunk_t ACON_chunk
= {0};
787 riff_chunk_t anih_chunk
= {0};
788 riff_chunk_t fram_chunk
= {0};
789 riff_chunk_t rate_chunk
= {0};
790 riff_chunk_t seq_chunk
= {0};
791 const unsigned char *icon_chunk
;
792 const unsigned char *icon_data
;
794 /* Find the root chunk */
795 riff_find_chunk( ANI_ACON_ID
, ANI_RIFF_ID
, &root_chunk
, &ACON_chunk
);
796 if (!ACON_chunk
.data
)
798 ERR("Failed to get root chunk.\n");
802 /* Find the header chunk */
803 riff_find_chunk( ANI_anih_ID
, 0, &ACON_chunk
, &anih_chunk
);
804 if (!ACON_chunk
.data
)
806 ERR("Failed to get header chunk.\n");
809 pHeader
= (ani_header
*)anih_chunk
.data
;
810 dump_ani_header(pHeader
);
812 /* Set up the master data */
813 pCurData
->CURSORF_flags
|= CURSORF_ACON
;
814 pCurData
->cpcur
= pHeader
->num_frames
;
815 pCurData
->cicur
= pHeader
->num_steps
;
816 pCurData
->iicur
= pHeader
->display_rate
;
818 /* Get the sequences */
819 if (pHeader
->flags
& ANI_FLAG_SEQUENCE
)
821 riff_find_chunk( ANI_seq__ID
, 0, &ACON_chunk
, &seq_chunk
);
824 ERR("No sequence data although the flag is set!\n");
829 /* Get the frame rates */
830 riff_find_chunk( ANI_rate_ID
, 0, &ACON_chunk
, &rate_chunk
);
832 pCurData
->ajifRate
= (INT
*)rate_chunk
.data
;
834 /* Get the frames chunk */
835 riff_find_chunk( ANI_fram_ID
, ANI_LIST_ID
, &ACON_chunk
, &fram_chunk
);
836 if (!fram_chunk
.data
)
838 ERR("Failed to get icon list.\n");
841 icon_chunk
= fram_chunk
.data
;
842 icon_data
= fram_chunk
.data
+ (2 * sizeof(DWORD
));
844 if(pHeader
->num_frames
> 1)
846 /* Allocate frame descriptors, step indices and rates */
847 pCurData
->aspcur
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
848 pHeader
->num_frames
* sizeof(CURSORDATA
) + pHeader
->num_steps
* (sizeof(DWORD
) + sizeof(INT
)));
849 if(!pCurData
->aspcur
)
851 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
854 pCurData
->aicur
= (DWORD
*)(pCurData
->aspcur
+ pHeader
->num_frames
);
855 pCurData
->ajifRate
= (INT
*)(pCurData
->aicur
+ pHeader
->num_steps
);
858 for(i
=0; i
< pHeader
->num_frames
; i
++)
860 CURSORDATA
* pFrameData
;
861 const DWORD chunk_size
= *(const DWORD
*)(icon_chunk
+ sizeof(DWORD
));
862 const BITMAPINFO
* pbmi
;
864 if(pHeader
->num_frames
> 1)
865 pFrameData
= &pCurData
->aspcur
[i
];
867 pFrameData
= pCurData
;
869 pFrameData
->rt
= pCurData
->rt
;
871 if (pHeader
->flags
& ANI_FLAG_ICON
)
873 /* The chunks describe an icon file */
874 const CURSORICONFILEDIRENTRY
* pDirEntry
= get_best_icon_file_entry(
875 (const CURSORICONFILEDIR
*) icon_data
,
883 ERR("Unable to find the right file entry for frame %d.\n", i
);
886 pFrameData
->xHotspot
= pDirEntry
->xHotspot
;
887 pFrameData
->yHotspot
= pDirEntry
->yHotspot
;
888 if(!pHeader
->width
|| !pHeader
->height
)
890 pFrameData
->cx
= pDirEntry
->bWidth
;
891 pFrameData
->cy
= pDirEntry
->bHeight
;
895 pFrameData
->cx
= pHeader
->width
;
896 pFrameData
->cy
= pHeader
->height
;
898 pbmi
= (const BITMAPINFO
*) (icon_data
+ pDirEntry
->dwDIBOffset
);
902 /* The chunks just describe bitmaps */
903 pbmi
= (const BITMAPINFO
*)icon_data
;
904 pFrameData
->xHotspot
= pFrameData
->yHotspot
= 0;
907 /* Do the real work */
908 CURSORICON_GetCursorDataFromBMI(pFrameData
, pbmi
);
910 if(pHeader
->num_frames
> 1)
911 pFrameData
->CURSORF_flags
|= CURSORF_ACONFRAME
;
913 pFrameData
->CURSORF_flags
&= ~CURSORF_ACON
;
917 icon_chunk
+= chunk_size
+ (2 * sizeof(DWORD
));
918 icon_data
= icon_chunk
+ (2 * sizeof(DWORD
));
921 if(pHeader
->num_frames
<= 1)
925 CopyMemory(pCurData
->ajifRate
, rate_chunk
.data
, pHeader
->num_steps
* sizeof(INT
));
928 for(i
=0; i
< pHeader
->num_steps
; i
++)
929 pCurData
->ajifRate
[i
] = pHeader
->display_rate
;
932 if (pHeader
->flags
& ANI_FLAG_SEQUENCE
)
934 CopyMemory(pCurData
->aicur
, seq_chunk
.data
, pHeader
->num_steps
* sizeof(DWORD
));
938 for(i
=0; i
< pHeader
->num_steps
; i
++)
939 pCurData
->aicur
[i
] = i
;
945 HeapFree(GetProcessHeap(), 0, pCurData
->aspcur
);
946 ZeroMemory(pCurData
, sizeof(CURSORDATA
));
954 _In_opt_ HINSTANCE hinst
,
955 _In_ LPCWSTR lpszName
,
961 const BITMAPINFO
* pbmi
;
962 BITMAPINFO
* pbmiScaled
= NULL
;
963 BITMAPINFO
* pbmiCopy
= NULL
;
964 const VOID
* pvMapping
= NULL
;
966 HGLOBAL hgRsrc
= NULL
;
969 HDC hdcScreen
= NULL
;
971 HBITMAP hbmpOld
, hbmpRet
= NULL
;
976 /* Map the bitmap info */
977 if(fuLoad
& LR_LOADFROMFILE
)
979 const BITMAPFILEHEADER
* pbmfh
;
981 pvMapping
= map_fileW(lpszName
, NULL
);
985 if (pbmfh
->bfType
!= 0x4d42 /* 'BM' */)
987 WARN("Invalid/unsupported bitmap format!\n");
990 pbmi
= (const BITMAPINFO
*)(pbmfh
+ 1);
992 /* Get the image bits */
994 dwOffset
= pbmfh
->bfOffBits
- sizeof(BITMAPFILEHEADER
);
1000 /* Caller wants an OEM bitmap */
1002 hinst
= User32Instance
;
1003 hrsrc
= FindResourceW(hinst
, lpszName
, RT_BITMAP
);
1006 hgRsrc
= LoadResource(hinst
, hrsrc
);
1009 pbmi
= LockResource(hgRsrc
);
1015 if(DIB_GetBitmapInfo(&pbmi
->bmiHeader
, &width
, &height
, &bpp
, &compr
) == -1)
1017 if((width
> 65535) || (height
> 65535))
1024 cyDesired
= -cyDesired
;
1026 iBMISize
= bitmap_info_size(pbmi
, DIB_RGB_COLORS
);
1028 /* Get a pointer to the image data */
1029 pvBits
= (char*)pbmi
+ (dwOffset
? dwOffset
: iBMISize
);
1031 /* Create a copy of the info describing the bitmap in the file */
1032 pbmiCopy
= HeapAlloc(GetProcessHeap(), 0, iBMISize
);
1035 CopyMemory(pbmiCopy
, pbmi
, iBMISize
);
1037 /* Fix it up, if needed */
1038 if(fuLoad
& (LR_LOADTRANSPARENT
| LR_LOADMAP3DCOLORS
))
1040 WORD bpp
, incr
, numColors
;
1043 COLORREF crWindow
, cr3DShadow
, cr3DFace
, cr3DLight
;
1044 BYTE pixel
= *((BYTE
*)pvBits
);
1047 if(pbmiCopy
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
1049 bpp
= ((BITMAPCOREHEADER
*)&pbmiCopy
->bmiHeader
)->bcBitCount
;
1050 numColors
= 1 << bpp
;
1051 /* BITMAPCOREINFO holds RGBTRIPLEs */
1056 bpp
= pbmiCopy
->bmiHeader
.biBitCount
;
1057 /* BITMAPINFOHEADER holds RGBQUADs */
1059 numColors
= pbmiCopy
->bmiHeader
.biClrUsed
;
1060 if(numColors
> 256) numColors
= 256;
1061 if (!numColors
&& (bpp
<= 8)) numColors
= 1 << bpp
;
1067 pbmiColors
= (char*)pbmiCopy
+ pbmiCopy
->bmiHeader
.biSize
;
1069 /* Get the relevant colors */
1070 crWindow
= GetSysColor(COLOR_WINDOW
);
1071 cr3DShadow
= GetSysColor(COLOR_3DSHADOW
);
1072 cr3DFace
= GetSysColor(COLOR_3DFACE
);
1073 cr3DLight
= GetSysColor(COLOR_3DLIGHT
);
1075 /* Fix the transparent palette entry */
1076 if(fuLoad
& LR_LOADTRANSPARENT
)
1080 case 1: pixel
>>= 7; break;
1081 case 4: pixel
>>= 4; break;
1084 FIXME("Unhandled bit depth %d.\n", bpp
);
1088 if(pixel
>= numColors
)
1090 ERR("Wrong pixel passed in.\n");
1094 /* If both flags are set, we must use COLOR_3DFACE */
1095 if(fuLoad
& LR_LOADMAP3DCOLORS
) crWindow
= cr3DFace
;
1097 /* Define the color */
1098 ptr
= (RGBTRIPLE
*)(pbmiColors
+ pixel
*incr
);
1099 ptr
->rgbtBlue
= GetBValue(crWindow
);
1100 ptr
->rgbtGreen
= GetGValue(crWindow
);
1101 ptr
->rgbtRed
= GetRValue(crWindow
);
1105 /* If we are here, then LR_LOADMAP3DCOLORS is set without LR_TRANSPARENT */
1106 for(i
= 0; i
<numColors
; i
++)
1108 ptr
= (RGBTRIPLE
*)(pbmiColors
+ i
*incr
);
1109 if((ptr
->rgbtBlue
== ptr
->rgbtRed
) && (ptr
->rgbtBlue
== ptr
->rgbtGreen
))
1111 if(ptr
->rgbtBlue
== 128)
1113 ptr
->rgbtBlue
= GetBValue(cr3DShadow
);
1114 ptr
->rgbtGreen
= GetGValue(cr3DShadow
);
1115 ptr
->rgbtRed
= GetRValue(cr3DShadow
);
1117 if(ptr
->rgbtBlue
== 192)
1119 ptr
->rgbtBlue
= GetBValue(cr3DFace
);
1120 ptr
->rgbtGreen
= GetGValue(cr3DFace
);
1121 ptr
->rgbtRed
= GetRValue(cr3DFace
);
1123 if(ptr
->rgbtBlue
== 223)
1125 ptr
->rgbtBlue
= GetBValue(cr3DLight
);
1126 ptr
->rgbtGreen
= GetGValue(cr3DLight
);
1127 ptr
->rgbtRed
= GetRValue(cr3DLight
);
1134 if(fuLoad
& LR_CREATEDIBSECTION
)
1136 /* Allocate the BMI describing the new bitmap */
1137 pbmiScaled
= HeapAlloc(GetProcessHeap(), 0, iBMISize
);
1140 CopyMemory(pbmiScaled
, pbmiCopy
, iBMISize
);
1143 if(pbmiScaled
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
1145 BITMAPCOREHEADER
* pbmch
= (BITMAPCOREHEADER
*)&pbmiScaled
->bmiHeader
;
1146 pbmch
->bcWidth
= cxDesired
;
1147 pbmch
->bcHeight
= cyDesired
;
1151 pbmiScaled
->bmiHeader
.biWidth
= cxDesired
;
1152 pbmiScaled
->bmiHeader
.biHeight
= cyDesired
;
1153 /* No compression for DIB sections */
1154 pbmiScaled
->bmiHeader
.biCompression
= BI_RGB
;
1158 /* Top-down image */
1159 if(cyDesired
< 0) cyDesired
= -cyDesired
;
1161 /* We need a device context */
1162 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
1165 hdc
= CreateCompatibleDC(hdcScreen
);
1169 /* Now create the bitmap */
1170 if(fuLoad
& LR_CREATEDIBSECTION
)
1171 hbmpRet
= CreateDIBSection(hdc
, pbmiScaled
, DIB_RGB_COLORS
, NULL
, 0, 0);
1174 if(is_dib_monochrome(pbmiCopy
) || (fuLoad
& LR_MONOCHROME
))
1175 hbmpRet
= CreateBitmap(cxDesired
, cyDesired
, 1, 1, NULL
);
1177 hbmpRet
= CreateCompatibleBitmap(hdcScreen
, cxDesired
, cyDesired
);
1183 hbmpOld
= SelectObject(hdc
, hbmpRet
);
1186 if(!StretchDIBits(hdc
, 0, 0, cxDesired
, cyDesired
,
1187 0, 0, pbmi
->bmiHeader
.biWidth
, pbmi
->bmiHeader
.biHeight
,
1188 pvBits
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
))
1190 ERR("StretchDIBits failed!.\n");
1191 SelectObject(hdc
, hbmpOld
);
1192 DeleteObject(hbmpRet
);
1197 SelectObject(hdc
, hbmpOld
);
1201 DeleteDC(hdcScreen
);
1205 HeapFree(GetProcessHeap(), 0, pbmiScaled
);
1207 HeapFree(GetProcessHeap(), 0, pbmiCopy
);
1209 UnmapViewOfFile( pvMapping
);
1211 FreeResource(hgRsrc
);
1219 CURSORICON_LoadFromFileW(
1220 _In_ LPCWSTR lpszName
,
1227 const CURSORICONFILEDIRENTRY
*entry
;
1228 const CURSORICONFILEDIR
*dir
;
1231 HANDLE hCurIcon
= NULL
;
1232 CURSORDATA cursorData
;
1234 TRACE("loading %s\n", debugstr_w( lpszName
));
1236 bits
= map_fileW( lpszName
, &filesize
);
1240 /* Check for .ani. */
1241 if (memcmp( bits
, "RIFF", 4 ) == 0)
1247 dir
= (CURSORICONFILEDIR
*) bits
;
1248 entry
= get_best_icon_file_entry(dir
, filesize
, cxDesired
, cyDesired
, bIcon
, fuLoad
);
1252 /* Fix dimensions */
1253 if(!cxDesired
) cxDesired
= entry
->bWidth
;
1254 if(!cyDesired
) cyDesired
= entry
->bHeight
;
1255 /* A bit of preparation */
1256 ZeroMemory(&cursorData
, sizeof(cursorData
));
1259 cursorData
.xHotspot
= entry
->xHotspot
;
1260 cursorData
.yHotspot
= entry
->yHotspot
;
1262 cursorData
.rt
= (USHORT
)((ULONG_PTR
)(bIcon
? RT_ICON
: RT_CURSOR
));
1265 if(!CURSORICON_GetCursorDataFromBMI(&cursorData
, (BITMAPINFO
*)(&bits
[entry
->dwDIBOffset
])))
1268 hCurIcon
= NtUserxCreateEmptyCurObject(FALSE
);
1273 if(!NtUserSetCursorIconData(hCurIcon
, NULL
, NULL
, &cursorData
))
1275 NtUserDestroyCursor(hCurIcon
, TRUE
);
1280 UnmapViewOfFile(bits
);
1285 DeleteObject(cursorData
.hbmMask
);
1286 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
1287 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
1288 UnmapViewOfFile(bits
);
1295 CURSORICON_LoadImageW(
1296 _In_opt_ HINSTANCE hinst
,
1297 _In_ LPCWSTR lpszName
,
1305 HANDLE handle
, hCurIcon
= NULL
;
1309 CURSORDATA cursorData
;
1311 UNICODE_STRING ustrRsrc
;
1312 UNICODE_STRING ustrModule
= {0, 0, NULL
};
1314 /* Fix width/height */
1315 if(fuLoad
& LR_DEFAULTSIZE
)
1317 if(!cxDesired
) cxDesired
= GetSystemMetrics(bIcon
? SM_CXICON
: SM_CXCURSOR
);
1318 if(!cyDesired
) cyDesired
= GetSystemMetrics(bIcon
? SM_CYICON
: SM_CYCURSOR
);
1321 if(fuLoad
& LR_LOADFROMFILE
)
1323 return CURSORICON_LoadFromFileW(lpszName
, cxDesired
, cyDesired
, fuLoad
, bIcon
);
1326 /* Check if caller wants OEM icons */
1328 hinst
= User32Instance
;
1330 if(fuLoad
& LR_SHARED
)
1332 DWORD size
= MAX_PATH
;
1333 FINDEXISTINGCURICONPARAM param
;
1335 TRACE("Checking for an LR_SHARED cursor/icon.\n");
1336 /* Prepare the resource name string */
1337 if(IS_INTRESOURCE(lpszName
))
1339 ustrRsrc
.Buffer
= (LPWSTR
)lpszName
;
1340 ustrRsrc
.Length
= 0;
1341 ustrRsrc
.MaximumLength
= 0;
1344 RtlInitUnicodeString(&ustrRsrc
, lpszName
);
1346 /* Prepare the module name string */
1347 ustrModule
.Buffer
= HeapAlloc(GetProcessHeap(), 0, size
*sizeof(WCHAR
));
1351 DWORD ret
= GetModuleFileNameW(hinst
, ustrModule
.Buffer
, size
);
1354 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1359 ustrModule
.Length
= ret
*sizeof(WCHAR
);
1360 ustrModule
.MaximumLength
= size
*sizeof(WCHAR
);
1364 ustrModule
.Buffer
= HeapReAlloc(GetProcessHeap(), 0, ustrModule
.Buffer
, size
*sizeof(WCHAR
));
1368 param
.bIcon
= bIcon
;
1369 param
.cx
= cxDesired
;
1370 param
.cy
= cyDesired
;
1371 hCurIcon
= NtUserFindExistingCursorIcon(&ustrModule
, &ustrRsrc
, ¶m
);
1374 /* Woohoo, got it! */
1376 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1381 /* Find resource ID */
1382 hrsrc
= FindResourceW(
1385 bIcon
? RT_GROUP_ICON
: RT_GROUP_CURSOR
);
1387 /* We let FindResource, LoadResource, etc. call SetLastError */
1391 handle
= LoadResource(hinst
, hrsrc
);
1395 dir
= LockResource(handle
);
1399 wResId
= LookupIconIdFromDirectoryEx((PBYTE
)dir
, bIcon
, cxDesired
, cyDesired
, fuLoad
);
1400 FreeResource(handle
);
1402 /* Get the relevant resource pointer */
1403 hrsrc
= FindResourceW(
1405 MAKEINTRESOURCEW(wResId
),
1406 bIcon
? RT_ICON
: RT_CURSOR
);
1410 handle
= LoadResource(hinst
, hrsrc
);
1414 bits
= LockResource(handle
);
1417 FreeResource(handle
);
1421 ZeroMemory(&cursorData
, sizeof(cursorData
));
1423 /* This is from resource */
1424 cursorData
.CURSORF_flags
= CURSORF_FROMRESOURCE
;
1426 if(dir
->idType
== 2)
1428 /* idType == 2 for cursor resources */
1429 SHORT
* ptr
= (SHORT
*)bits
;
1430 cursorData
.xHotspot
= ptr
[0];
1431 cursorData
.yHotspot
= ptr
[1];
1432 bits
+= 2*sizeof(SHORT
);
1434 cursorData
.cx
= cxDesired
;
1435 cursorData
.cy
= cyDesired
;
1436 cursorData
.rt
= (USHORT
)((ULONG_PTR
)(bIcon
? RT_ICON
: RT_CURSOR
));
1438 /* Get the bitmaps */
1439 bStatus
= CURSORICON_GetCursorDataFromBMI(
1443 FreeResource( handle
);
1448 /* Create the handle */
1449 hCurIcon
= NtUserxCreateEmptyCurObject(FALSE
);
1456 if(fuLoad
& LR_SHARED
)
1458 cursorData
.CURSORF_flags
|= CURSORF_LRSHARED
;
1459 bStatus
= NtUserSetCursorIconData(hCurIcon
, &ustrModule
, &ustrRsrc
, &cursorData
);
1462 bStatus
= NtUserSetCursorIconData(hCurIcon
, NULL
, NULL
, &cursorData
);
1466 NtUserDestroyCursor(hCurIcon
, TRUE
);
1471 if(ustrModule
.Buffer
)
1472 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1476 if(ustrModule
.Buffer
)
1477 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1478 DeleteObject(cursorData
.hbmMask
);
1479 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
1480 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
1499 objSize
= GetObjectW( hnd
, sizeof(ds
), &ds
);
1500 if (!objSize
) return 0;
1501 if ((desiredx
< 0) || (desiredy
< 0)) return 0;
1503 if (flags
& LR_COPYFROMRESOURCE
)
1505 FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
1508 if (flags
& LR_COPYRETURNORG
)
1510 FIXME("The flag LR_COPYRETURNORG is not implemented for bitmaps\n");
1513 if (desiredx
== 0) desiredx
= ds
.dsBm
.bmWidth
;
1514 if (desiredy
== 0) desiredy
= ds
.dsBm
.bmHeight
;
1516 /* Allocate memory for a BITMAPINFOHEADER structure and a
1517 color table. The maximum number of colors in a color table
1518 is 256 which corresponds to a bitmap with depth 8.
1519 Bitmaps with higher depths don't have color tables. */
1520 bi
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
));
1523 bi
->bmiHeader
.biSize
= sizeof(bi
->bmiHeader
);
1524 bi
->bmiHeader
.biPlanes
= ds
.dsBm
.bmPlanes
;
1525 bi
->bmiHeader
.biBitCount
= ds
.dsBm
.bmBitsPixel
;
1526 bi
->bmiHeader
.biCompression
= BI_RGB
;
1528 if (flags
& LR_CREATEDIBSECTION
)
1530 /* Create a DIB section. LR_MONOCHROME is ignored */
1532 HDC dc
= CreateCompatibleDC(NULL
);
1534 if (objSize
== sizeof(DIBSECTION
))
1536 /* The source bitmap is a DIB.
1537 Get its attributes to create an exact copy */
1538 memcpy(bi
, &ds
.dsBmih
, sizeof(BITMAPINFOHEADER
));
1541 bi
->bmiHeader
.biWidth
= desiredx
;
1542 bi
->bmiHeader
.biHeight
= desiredy
;
1544 /* Get the color table or the color masks */
1545 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
1547 res
= CreateDIBSection(dc
, bi
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
1552 /* Create a device-dependent bitmap */
1554 BOOL monochrome
= (flags
& LR_MONOCHROME
);
1556 if (objSize
== sizeof(DIBSECTION
))
1558 /* The source bitmap is a DIB section.
1559 Get its attributes */
1560 HDC dc
= CreateCompatibleDC(NULL
);
1561 bi
->bmiHeader
.biWidth
= ds
.dsBm
.bmWidth
;
1562 bi
->bmiHeader
.biHeight
= ds
.dsBm
.bmHeight
;
1563 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
1566 if (!monochrome
&& ds
.dsBm
.bmBitsPixel
== 1)
1568 /* Look if the colors of the DIB are black and white */
1571 (bi
->bmiColors
[0].rgbRed
== 0xff
1572 && bi
->bmiColors
[0].rgbGreen
== 0xff
1573 && bi
->bmiColors
[0].rgbBlue
== 0xff
1574 && bi
->bmiColors
[0].rgbReserved
== 0
1575 && bi
->bmiColors
[1].rgbRed
== 0
1576 && bi
->bmiColors
[1].rgbGreen
== 0
1577 && bi
->bmiColors
[1].rgbBlue
== 0
1578 && bi
->bmiColors
[1].rgbReserved
== 0)
1580 (bi
->bmiColors
[0].rgbRed
== 0
1581 && bi
->bmiColors
[0].rgbGreen
== 0
1582 && bi
->bmiColors
[0].rgbBlue
== 0
1583 && bi
->bmiColors
[0].rgbReserved
== 0
1584 && bi
->bmiColors
[1].rgbRed
== 0xff
1585 && bi
->bmiColors
[1].rgbGreen
== 0xff
1586 && bi
->bmiColors
[1].rgbBlue
== 0xff
1587 && bi
->bmiColors
[1].rgbReserved
== 0);
1590 else if (!monochrome
)
1592 monochrome
= ds
.dsBm
.bmBitsPixel
== 1;
1597 res
= CreateBitmap(desiredx
, desiredy
, 1, 1, NULL
);
1601 HDC screenDC
= GetDC(NULL
);
1602 res
= CreateCompatibleBitmap(screenDC
, desiredx
, desiredy
);
1603 ReleaseDC(NULL
, screenDC
);
1609 /* Only copy the bitmap if it's a DIB section or if it's
1610 compatible to the screen */
1613 if (objSize
== sizeof(DIBSECTION
))
1615 copyContents
= TRUE
;
1619 HDC screenDC
= GetDC(NULL
);
1620 int screen_depth
= GetDeviceCaps(screenDC
, BITSPIXEL
);
1621 ReleaseDC(NULL
, screenDC
);
1623 copyContents
= (ds
.dsBm
.bmBitsPixel
== 1 || ds
.dsBm
.bmBitsPixel
== screen_depth
);
1628 /* The source bitmap may already be selected in a device context,
1629 use GetDIBits/StretchDIBits and not StretchBlt */
1634 dc
= CreateCompatibleDC(NULL
);
1636 bi
->bmiHeader
.biWidth
= ds
.dsBm
.bmWidth
;
1637 bi
->bmiHeader
.biHeight
= ds
.dsBm
.bmHeight
;
1638 bi
->bmiHeader
.biSizeImage
= 0;
1639 bi
->bmiHeader
.biClrUsed
= 0;
1640 bi
->bmiHeader
.biClrImportant
= 0;
1642 /* Fill in biSizeImage */
1643 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
1644 bits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, bi
->bmiHeader
.biSizeImage
);
1650 /* Get the image bits of the source bitmap */
1651 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, bits
, bi
, DIB_RGB_COLORS
);
1653 /* Copy it to the destination bitmap */
1654 oldBmp
= SelectObject(dc
, res
);
1655 StretchDIBits(dc
, 0, 0, desiredx
, desiredy
,
1656 0, 0, ds
.dsBm
.bmWidth
, ds
.dsBm
.bmHeight
,
1657 bits
, bi
, DIB_RGB_COLORS
, SRCCOPY
);
1658 SelectObject(dc
, oldBmp
);
1660 HeapFree(GetProcessHeap(), 0, bits
);
1666 if (flags
& LR_COPYDELETEORG
)
1671 HeapFree(GetProcessHeap(), 0, bi
);
1677 CURSORICON_CopyImage(
1687 CURSORDATA CursorData
;
1689 if (fuFlags
& LR_COPYFROMRESOURCE
)
1691 /* Get the icon module/resource names */
1692 UNICODE_STRING ustrModule
;
1693 UNICODE_STRING ustrRsrc
;
1697 ustrModule
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
1698 ustrRsrc
.MaximumLength
= 256;
1700 ustrModule
.Buffer
= HeapAlloc(GetProcessHeap(), 0, ustrModule
.MaximumLength
);
1701 if (!ustrModule
.Buffer
)
1703 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1706 /* Keep track of the buffer for the resource, NtUserGetIconInfo might overwrite it */
1707 pvBuf
= HeapAlloc(GetProcessHeap(), 0, ustrRsrc
.MaximumLength
);
1710 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1711 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1714 ustrRsrc
.Buffer
= pvBuf
;
1718 if (!NtUserGetIconInfo(hicon
, NULL
, &ustrModule
, &ustrRsrc
, NULL
, FALSE
))
1720 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1721 HeapFree(GetProcessHeap(), 0, pvBuf
);
1725 if (ustrModule
.Length
&& (ustrRsrc
.Length
|| IS_INTRESOURCE(ustrRsrc
.Buffer
)))
1727 /* Buffers were big enough */
1731 /* Find which buffer were too small */
1732 if (!ustrModule
.Length
)
1735 ustrModule
.MaximumLength
*= 2;
1736 newBuffer
= HeapReAlloc(GetProcessHeap(), 0, ustrModule
.Buffer
, ustrModule
.MaximumLength
);
1737 if(!ustrModule
.Buffer
)
1739 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1742 ustrModule
.Buffer
= newBuffer
;
1745 if (!ustrRsrc
.Length
)
1747 ustrRsrc
.MaximumLength
*= 2;
1748 pvBuf
= HeapReAlloc(GetProcessHeap(), 0, ustrRsrc
.Buffer
, ustrRsrc
.MaximumLength
);
1751 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1754 ustrRsrc
.Buffer
= pvBuf
;
1758 /* NULL-terminate our strings */
1759 ustrModule
.Buffer
[ustrModule
.Length
/sizeof(WCHAR
)] = 0;
1760 if (!IS_INTRESOURCE(ustrRsrc
.Buffer
))
1761 ustrRsrc
.Buffer
[ustrRsrc
.Length
/sizeof(WCHAR
)] = 0;
1763 /* Get the module handle */
1764 if (!GetModuleHandleExW(0, ustrModule
.Buffer
, &hModule
))
1766 /* This should never happen */
1767 ERR("Invalid handle?.\n");
1768 SetLastError(ERROR_INVALID_PARAMETER
);
1772 /* Call the relevant function */
1773 ret
= CURSORICON_LoadImageW(
1778 fuFlags
& (LR_DEFAULTSIZE
| LR_SHARED
),
1781 FreeLibrary(hModule
);
1783 /* If we're here, that means that the passed icon is shared. Don't destroy it, even if LR_COPYDELETEORG is specified */
1785 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1786 HeapFree(GetProcessHeap(), 0, pvBuf
);
1788 TRACE("Returning 0x%08x.\n", ret
);
1793 /* This is a regular copy */
1794 if (fuFlags
& ~(LR_COPYDELETEORG
| LR_SHARED
))
1795 FIXME("Unimplemented flags: 0x%08x\n", fuFlags
);
1797 if (!GetIconInfo(hicon
, &ii
))
1799 ERR("GetIconInfo failed.\n");
1803 /* This is CreateIconIndirect with the LR_SHARED coat added */
1804 if (!CURSORICON_GetCursorDataFromIconInfo(&CursorData
, &ii
))
1807 if (fuFlags
& LR_SHARED
)
1808 CursorData
.CURSORF_flags
|= CURSORF_LRSHARED
;
1810 ret
= NtUserxCreateEmptyCurObject(FALSE
);
1814 if (!NtUserSetCursorIconData(ret
, NULL
, NULL
, &CursorData
))
1816 NtUserDestroyCursor(ret
, TRUE
);
1821 DeleteObject(ii
.hbmMask
);
1822 if (ii
.hbmColor
) DeleteObject(ii
.hbmColor
);
1824 if (ret
&& (fuFlags
& LR_COPYDELETEORG
))
1831 User32CallCopyImageFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
1833 PCOPYIMAGE_CALLBACK_ARGUMENTS Common
;
1835 Common
= (PCOPYIMAGE_CALLBACK_ARGUMENTS
) Arguments
;
1837 Result
= CopyImage(Common
->hImage
,
1843 return ZwCallbackReturn(&Result
, sizeof(HANDLE
), STATUS_SUCCESS
);
1847 /************* PUBLIC FUNCTIONS *******************/
1849 HANDLE WINAPI
CopyImage(
1857 TRACE("hImage=%p, uType=%u, cxDesired=%d, cyDesired=%d, fuFlags=%x\n",
1858 hImage
, uType
, cxDesired
, cyDesired
, fuFlags
);
1862 return BITMAP_CopyImage(hImage
, cxDesired
, cyDesired
, fuFlags
);
1865 return CURSORICON_CopyImage(hImage
, uType
== IMAGE_ICON
, cxDesired
, cyDesired
, fuFlags
);
1867 SetLastError(ERROR_INVALID_PARAMETER
);
1873 HICON WINAPI
CopyIcon(
1877 return CURSORICON_CopyImage(hIcon
, FALSE
, 0, 0, 0);
1880 BOOL WINAPI
DrawIcon(
1887 return DrawIconEx(hDC
, X
, Y
, hIcon
, 0, 0, 0, NULL
, DI_NORMAL
| DI_COMPAT
| DI_DEFAULTSIZE
);
1890 BOOL WINAPI
DrawIconEx(
1897 _In_ UINT istepIfAniCur
,
1898 _In_opt_ HBRUSH hbrFlickerFreeDraw
,
1902 return NtUserDrawIconEx(hdc
, xLeft
, yTop
, hIcon
, cxWidth
, cyWidth
,
1903 istepIfAniCur
, hbrFlickerFreeDraw
, diFlags
,
1907 BOOL WINAPI
GetIconInfo(
1909 _Out_ PICONINFO piconinfo
1912 return NtUserGetIconInfo(hIcon
, piconinfo
, NULL
, NULL
, NULL
, FALSE
);
1915 BOOL WINAPI
DestroyIcon(
1919 return NtUserDestroyCursor(hIcon
, FALSE
);
1922 HICON WINAPI
LoadIconA(
1923 _In_opt_ HINSTANCE hInstance
,
1924 _In_ LPCSTR lpIconName
1927 TRACE("%p, %s\n", hInstance
, debugstr_a(lpIconName
));
1929 return LoadImageA(hInstance
,
1934 LR_SHARED
| LR_DEFAULTSIZE
);
1937 HICON WINAPI
LoadIconW(
1938 _In_opt_ HINSTANCE hInstance
,
1939 _In_ LPCWSTR lpIconName
1942 TRACE("%p, %s\n", hInstance
, debugstr_w(lpIconName
));
1944 return LoadImageW(hInstance
,
1949 LR_SHARED
| LR_DEFAULTSIZE
);
1952 HCURSOR WINAPI
LoadCursorA(
1953 _In_opt_ HINSTANCE hInstance
,
1954 _In_ LPCSTR lpCursorName
1957 TRACE("%p, %s\n", hInstance
, debugstr_a(lpCursorName
));
1959 return LoadImageA(hInstance
,
1964 LR_SHARED
| LR_DEFAULTSIZE
);
1967 HCURSOR WINAPI
LoadCursorW(
1968 _In_opt_ HINSTANCE hInstance
,
1969 _In_ LPCWSTR lpCursorName
1972 TRACE("%p, %s\n", hInstance
, debugstr_w(lpCursorName
));
1974 return LoadImageW(hInstance
,
1979 LR_SHARED
| LR_DEFAULTSIZE
);
1982 HCURSOR WINAPI
LoadCursorFromFileA(
1983 _In_ LPCSTR lpFileName
1986 TRACE("%s\n", debugstr_a(lpFileName
));
1988 return LoadImageA(NULL
,
1993 LR_LOADFROMFILE
| LR_DEFAULTSIZE
);
1996 HCURSOR WINAPI
LoadCursorFromFileW(
1997 _In_ LPCWSTR lpFileName
2000 TRACE("%s\n", debugstr_w(lpFileName
));
2002 return LoadImageW(NULL
,
2007 LR_LOADFROMFILE
| LR_DEFAULTSIZE
);
2010 HBITMAP WINAPI
LoadBitmapA(
2011 _In_opt_ HINSTANCE hInstance
,
2012 _In_ LPCSTR lpBitmapName
2015 TRACE("%p, %s\n", hInstance
, debugstr_a(lpBitmapName
));
2017 return LoadImageA(hInstance
,
2025 HBITMAP WINAPI
LoadBitmapW(
2026 _In_opt_ HINSTANCE hInstance
,
2027 _In_ LPCWSTR lpBitmapName
2030 TRACE("%p, %s\n", hInstance
, debugstr_w(lpBitmapName
));
2032 return LoadImageW(hInstance
,
2040 HANDLE WINAPI
LoadImageA(
2041 _In_opt_ HINSTANCE hinst
,
2042 _In_ LPCSTR lpszName
,
2053 if (IS_INTRESOURCE(lpszName
))
2054 return LoadImageW(hinst
, (LPCWSTR
)lpszName
, uType
, cxDesired
, cyDesired
, fuLoad
);
2056 len
= MultiByteToWideChar( CP_ACP
, 0, lpszName
, -1, NULL
, 0 );
2057 u_name
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
2058 MultiByteToWideChar( CP_ACP
, 0, lpszName
, -1, u_name
, len
);
2060 res
= LoadImageW(hinst
, u_name
, uType
, cxDesired
, cyDesired
, fuLoad
);
2061 HeapFree(GetProcessHeap(), 0, u_name
);
2065 HANDLE WINAPI
LoadImageW(
2066 _In_opt_ HINSTANCE hinst
,
2067 _In_ LPCWSTR lpszName
,
2074 TRACE("hinst 0x%p, name %s, uType 0x%08x, cxDesired %d, cyDesired %d, fuLoad 0x%08x.\n",
2075 hinst
, debugstr_w(lpszName
), uType
, cxDesired
, cyDesired
, fuLoad
);
2076 /* Redirect to each implementation */
2080 return BITMAP_LoadImageW(hinst
, lpszName
, cxDesired
, cyDesired
, fuLoad
);
2083 return CURSORICON_LoadImageW(hinst
, lpszName
, cxDesired
, cyDesired
, fuLoad
, uType
== IMAGE_ICON
);
2085 SetLastError(ERROR_INVALID_PARAMETER
);
2091 int WINAPI
LookupIconIdFromDirectory(
2092 _In_ PBYTE presbits
,
2096 return LookupIconIdFromDirectoryEx( presbits
, fIcon
,
2097 fIcon
? GetSystemMetrics(SM_CXICON
) : GetSystemMetrics(SM_CXCURSOR
),
2098 fIcon
? GetSystemMetrics(SM_CYICON
) : GetSystemMetrics(SM_CYCURSOR
), fIcon
? 0 : LR_MONOCHROME
);
2101 int WINAPI
LookupIconIdFromDirectoryEx(
2102 _In_ PBYTE presbits
,
2110 CURSORICONDIR
* dir
= (CURSORICONDIR
*)presbits
;
2111 CURSORICONDIRENTRY
* entry
;
2112 int i
, numMatch
= 0, iIndex
= -1;
2113 WORD width
, height
, BitCount
= 0;
2114 BOOL notPaletted
= FALSE
;
2115 ULONG bestScore
= 0xFFFFFFFF, score
;
2117 TRACE("%p, %x, %i, %i, %x.\n", presbits
, fIcon
, cxDesired
, cyDesired
, Flags
);
2119 if(!(dir
&& !dir
->idReserved
&& (dir
->idType
& 3)))
2121 WARN("Invalid resource.\n");
2125 if(Flags
& LR_MONOCHROME
)
2130 icScreen
= CreateICW(DISPLAYW
, NULL
, NULL
, NULL
);
2134 bppDesired
= GetDeviceCaps(icScreen
, BITSPIXEL
);
2139 cxDesired
= Flags
& LR_DEFAULTSIZE
? GetSystemMetrics(fIcon
? SM_CXICON
: SM_CXCURSOR
) : 256;
2141 cyDesired
= Flags
& LR_DEFAULTSIZE
? GetSystemMetrics(fIcon
? SM_CYICON
: SM_CYCURSOR
) : 256;
2143 /* Find the best match for the desired size */
2144 for(i
= 0; i
< dir
->idCount
; i
++)
2146 entry
= &dir
->idEntries
[i
];
2147 width
= fIcon
? entry
->ResInfo
.icon
.bWidth
: entry
->ResInfo
.cursor
.wWidth
;
2148 /* Height is twice as big in cursor resources */
2149 height
= fIcon
? entry
->ResInfo
.icon
.bHeight
: entry
->ResInfo
.cursor
.wHeight
/2;
2150 /* 0 represents 256 */
2151 if(!width
) width
= 256;
2152 if(!height
) height
= 256;
2153 /* Calculate the "score" (lower is better) */
2154 score
= 2*(abs(width
- cxDesired
) + abs(height
- cyDesired
));
2155 if( score
> bestScore
)
2157 /* Bigger than requested lowers the score */
2158 if(width
> cxDesired
)
2159 score
-= width
- cxDesired
;
2160 if(height
> cyDesired
)
2161 score
-= height
- cyDesired
;
2162 if(score
> bestScore
)
2164 if(score
== bestScore
)
2166 if(entry
->wBitCount
> BitCount
)
2167 BitCount
= entry
->wBitCount
;
2174 BitCount
= entry
->wBitCount
;
2179 /* Only one entry fits the asked dimensions */
2180 return dir
->idEntries
[iIndex
].wResId
;
2183 /* Avoid paletted icons on non-paletted device */
2184 if (bppDesired
> 8 && BitCount
> 8)
2189 /* Now find the entry with the best depth */
2190 for(i
= 0; i
< dir
->idCount
; i
++)
2192 entry
= &dir
->idEntries
[i
];
2193 width
= fIcon
? entry
->ResInfo
.icon
.bWidth
: entry
->ResInfo
.cursor
.wWidth
;
2194 height
= fIcon
? entry
->ResInfo
.icon
.bHeight
: entry
->ResInfo
.cursor
.wHeight
/2;
2195 /* 0 represents 256 */
2196 if(!width
) width
= 256;
2197 if(!height
) height
= 256;
2198 /* Check if this is the best match we had */
2199 score
= 2*(abs(width
- cxDesired
) + abs(height
- cyDesired
));
2200 if(width
> cxDesired
)
2201 score
-= width
- cxDesired
;
2202 if(height
> cyDesired
)
2203 score
-= height
- cyDesired
;
2204 if(score
!= bestScore
)
2207 if(entry
->wBitCount
== bppDesired
)
2208 return entry
->wResId
;
2209 /* We take the highest possible but smaller than the display depth */
2210 if((entry
->wBitCount
> BitCount
) && (entry
->wBitCount
< bppDesired
))
2212 /* Avoid paletted icons on non paletted devices */
2213 if ((entry
->wBitCount
<= 8) && notPaletted
)
2216 BitCount
= entry
->wBitCount
;
2221 return dir
->idEntries
[iIndex
].wResId
;
2223 /* No inferior or equal depth available. Get the smallest bigger one */
2226 for(i
= 0; i
< dir
->idCount
; i
++)
2228 entry
= &dir
->idEntries
[i
];
2229 width
= fIcon
? entry
->ResInfo
.icon
.bWidth
: entry
->ResInfo
.cursor
.wWidth
;
2230 height
= fIcon
? entry
->ResInfo
.icon
.bHeight
: entry
->ResInfo
.cursor
.wHeight
/2;
2231 /* 0 represents 256 */
2232 if(!width
) width
= 256;
2233 if(!height
) height
= 256;
2234 /* Check if this is the best match we had */
2235 score
= 2*(abs(width
- cxDesired
) + abs(height
- cyDesired
));
2236 if(width
> cxDesired
)
2237 score
-= width
- cxDesired
;
2238 if(height
> cyDesired
)
2239 score
-= height
- cyDesired
;
2240 if(score
!= bestScore
)
2242 /* Check the bit depth */
2243 if(entry
->wBitCount
< BitCount
)
2245 if((entry
->wBitCount
<= 8) && notPaletted
)
2248 BitCount
= entry
->wBitCount
;
2252 return dir
->idEntries
[iIndex
].wResId
;
2257 HICON WINAPI
CreateIcon(
2258 _In_opt_ HINSTANCE hInstance
,
2262 _In_ BYTE cBitsPixel
,
2263 _In_
const BYTE
*lpbANDbits
,
2264 _In_
const BYTE
*lpbXORbits
2270 TRACE_(icon
)("%dx%d, planes %d, bpp %d, xor %p, and %p\n",
2271 nWidth
, nHeight
, cPlanes
, cBitsPixel
, lpbXORbits
, lpbANDbits
);
2274 iinfo
.xHotspot
= nWidth
/ 2;
2275 iinfo
.yHotspot
= nHeight
/ 2;
2276 if (cPlanes
* cBitsPixel
> 1)
2278 iinfo
.hbmColor
= CreateBitmap( nWidth
, nHeight
, cPlanes
, cBitsPixel
, lpbXORbits
);
2279 iinfo
.hbmMask
= CreateBitmap( nWidth
, nHeight
, 1, 1, lpbANDbits
);
2283 iinfo
.hbmMask
= CreateBitmap( nWidth
, nHeight
* 2, 1, 1, lpbANDbits
);
2284 iinfo
.hbmColor
= NULL
;
2287 hIcon
= CreateIconIndirect( &iinfo
);
2289 DeleteObject( iinfo
.hbmMask
);
2290 if (iinfo
.hbmColor
) DeleteObject( iinfo
.hbmColor
);
2295 HICON WINAPI
CreateIconFromResource(
2296 _In_ PBYTE presbits
,
2297 _In_ DWORD dwResSize
,
2302 return CreateIconFromResourceEx( presbits
, dwResSize
, fIcon
, dwVer
, 0, 0, LR_DEFAULTSIZE
| LR_SHARED
);
2305 HICON WINAPI
CreateIconFromResourceEx(
2306 _In_ PBYTE pbIconBits
,
2307 _In_ DWORD cbIconBits
,
2309 _In_ DWORD dwVersion
,
2315 CURSORDATA cursorData
;
2319 TRACE("%p, %lu, %lu, %lu, %i, %i, %lu.\n", pbIconBits
, cbIconBits
, fIcon
, dwVersion
, cxDesired
, cyDesired
, uFlags
);
2321 if(uFlags
& LR_DEFAULTSIZE
)
2323 if(!cxDesired
) cxDesired
= GetSystemMetrics(fIcon
? SM_CXICON
: SM_CXCURSOR
);
2324 if(!cyDesired
) cyDesired
= GetSystemMetrics(fIcon
? SM_CYICON
: SM_CYCURSOR
);
2327 ZeroMemory(&cursorData
, sizeof(cursorData
));
2328 cursorData
.cx
= cxDesired
;
2329 cursorData
.cy
= cyDesired
;
2330 cursorData
.rt
= (USHORT
)((ULONG_PTR
)(fIcon
? RT_ICON
: RT_CURSOR
));
2332 /* Convert to win32k-ready data */
2333 if(!memcmp(pbIconBits
, "RIFF", 4))
2335 if(!CURSORICON_GetCursorDataFromANI(&cursorData
, pbIconBits
, cbIconBits
, uFlags
))
2337 ERR("Could not get cursor data from .ani.\n");
2340 isAnimated
= !!(cursorData
.CURSORF_flags
& CURSORF_ACON
);
2344 /* It is possible to pass Icon Directories to this API */
2345 int wResId
= LookupIconIdFromDirectoryEx(pbIconBits
, fIcon
, cxDesired
, cyDesired
, uFlags
);
2346 HANDLE ResHandle
= NULL
;
2351 CURSORICONDIR
* pCurIconDir
= (CURSORICONDIR
*)pbIconBits
;
2353 TRACE("Pointer points to a directory structure.\n");
2355 /* So this is a pointer to an icon directory structure. Find the module */
2356 if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
| GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
,
2357 (LPCWSTR
)pbIconBits
,
2363 /* Check we were given the right type of resource */
2364 if((fIcon
&& pCurIconDir
->idType
== 2) || (!fIcon
&& pCurIconDir
->idType
== 1))
2366 WARN("Got a %s directory pointer, but called for a %s", fIcon
? "cursor" : "icon", fIcon
? "icon" : "cursor");
2370 /* Get the relevant resource pointer */
2371 hrsrc
= FindResourceW(
2373 MAKEINTRESOURCEW(wResId
),
2374 fIcon
? RT_ICON
: RT_CURSOR
);
2378 ResHandle
= LoadResource(hinst
, hrsrc
);
2382 pbIconBits
= LockResource(ResHandle
);
2385 FreeResource(ResHandle
);
2391 WORD
* pt
= (WORD
*)pbIconBits
;
2392 cursorData
.xHotspot
= *pt
++;
2393 cursorData
.yHotspot
= *pt
++;
2394 pbIconBits
= (PBYTE
)pt
;
2397 if (!CURSORICON_GetCursorDataFromBMI(&cursorData
, (BITMAPINFO
*)pbIconBits
))
2399 ERR("Couldn't fill the CURSORDATA structure.\n");
2401 FreeResource(ResHandle
);
2405 FreeResource(ResHandle
);
2409 if (uFlags
& LR_SHARED
)
2410 cursorData
.CURSORF_flags
|= CURSORF_LRSHARED
;
2412 hIcon
= NtUserxCreateEmptyCurObject(isAnimated
);
2416 if(!NtUserSetCursorIconData(hIcon
, NULL
, NULL
, &cursorData
))
2418 ERR("NtUserSetCursorIconData failed.\n");
2419 NtUserDestroyCursor(hIcon
, TRUE
);
2424 HeapFree(GetProcessHeap(), 0, cursorData
.aspcur
);
2431 HeapFree(GetProcessHeap(), 0, cursorData
.aspcur
);
2432 DeleteObject(cursorData
.hbmMask
);
2433 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
2434 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
2439 HICON WINAPI
CreateIconIndirect(
2440 _In_ PICONINFO piconinfo
2443 /* As simple as creating a handle, and let win32k deal with the bitmaps */
2445 CURSORDATA cursorData
;
2447 TRACE("%p.\n", piconinfo
);
2449 ZeroMemory(&cursorData
, sizeof(cursorData
));
2451 if(!CURSORICON_GetCursorDataFromIconInfo(&cursorData
, piconinfo
))
2454 hiconRet
= NtUserxCreateEmptyCurObject(FALSE
);
2458 if(!NtUserSetCursorIconData(hiconRet
, NULL
, NULL
, &cursorData
))
2460 NtUserDestroyCursor(hiconRet
, FALSE
);
2464 TRACE("Returning 0x%08x.\n", hiconRet
);
2470 DeleteObject(cursorData
.hbmMask
);
2471 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
2472 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
2477 HCURSOR WINAPI
CreateCursor(
2478 _In_opt_ HINSTANCE hInst
,
2483 _In_
const VOID
*pvANDPlane
,
2484 _In_
const VOID
*pvXORPlane
2490 TRACE_(cursor
)("%dx%d spot=%d,%d xor=%p and=%p\n",
2491 nWidth
, nHeight
, xHotSpot
, yHotSpot
, pvXORPlane
, pvANDPlane
);
2494 info
.xHotspot
= xHotSpot
;
2495 info
.yHotspot
= yHotSpot
;
2496 info
.hbmMask
= CreateBitmap( nWidth
, nHeight
, 1, 1, pvANDPlane
);
2497 info
.hbmColor
= CreateBitmap( nWidth
, nHeight
, 1, 1, pvXORPlane
);
2498 hCursor
= CreateIconIndirect( &info
);
2499 DeleteObject( info
.hbmMask
);
2500 DeleteObject( info
.hbmColor
);
2504 BOOL WINAPI
SetSystemCursor(
2513 BOOL WINAPI
SetCursorPos(
2518 return NtUserxSetCursorPos(X
,Y
);
2521 BOOL WINAPI
GetCursorPos(
2522 _Out_ LPPOINT lpPoint
2525 return NtUserxGetCursorPos(lpPoint
);
2528 int WINAPI
ShowCursor(
2532 return NtUserxShowCursor(bShow
);
2535 HCURSOR WINAPI
GetCursor(void)
2537 return (HCURSOR
)NtUserGetThreadState(THREADSTATE_GETCURSOR
);
2540 BOOL WINAPI
DestroyCursor(
2541 _In_ HCURSOR hCursor
2544 return NtUserDestroyCursor(hCursor
, FALSE
);
2549 GetCursorFrameInfo(HCURSOR hCursor
, DWORD reserved
, DWORD istep
, PINT rate_jiffies
, DWORD
*num_steps
)
2551 return NtUserGetCursorFrameInfo(hCursor
, istep
, rate_jiffies
, num_steps
);