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 if ( dwFileSize
< sizeof(*dir
) )
399 if ( dwFileSize
< (sizeof(*dir
) + sizeof(dir
->idEntries
[0])*(dir
->idCount
-1)) )
404 * We allocate a buffer, fake it as if it was a pointer to a resource in a module,
405 * pass it to LookupIconIdFromDirectoryEx and get back the index we have to use
407 fakeDir
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(CURSORICONDIR
, idEntries
[dir
->idCount
]));
410 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
413 fakeDir
->idReserved
= 0;
414 fakeDir
->idType
= dir
->idType
;
415 fakeDir
->idCount
= dir
->idCount
;
416 for(i
= 0; i
<dir
->idCount
; i
++)
418 fakeEntry
= &fakeDir
->idEntries
[i
];
419 entry
= &dir
->idEntries
[i
];
420 /* Take this as an occasion to perform a size check */
421 if((entry
->dwDIBOffset
+ entry
->dwDIBSize
) > dwFileSize
)
423 ERR("Corrupted icon file?.\n");
424 HeapFree(GetProcessHeap(), 0, fakeDir
);
427 /* File icon/cursors are not like resource ones */
430 fakeEntry
->ResInfo
.icon
.bWidth
= entry
->bWidth
;
431 fakeEntry
->ResInfo
.icon
.bHeight
= entry
->bHeight
;
432 fakeEntry
->ResInfo
.icon
.bColorCount
= 0;
433 fakeEntry
->ResInfo
.icon
.bReserved
= 0;
437 fakeEntry
->ResInfo
.cursor
.wWidth
= entry
->bWidth
;
438 fakeEntry
->ResInfo
.cursor
.wHeight
= entry
->bHeight
;
440 /* Let's assume there's always one plane */
441 fakeEntry
->wPlanes
= 1;
442 /* We must get the bitcount from the BITMAPINFOHEADER itself */
443 fakeEntry
->wBitCount
= ((BITMAPINFOHEADER
*)((char *)dir
+ entry
->dwDIBOffset
))->biBitCount
;
444 fakeEntry
->dwBytesInRes
= entry
->dwDIBSize
;
445 fakeEntry
->wResId
= i
+ 1;
448 /* Now call LookupIconIdFromResourceEx */
449 i
= LookupIconIdFromDirectoryEx((PBYTE
)fakeDir
, bIcon
, cxDesired
, cyDesired
, fuLoad
& LR_MONOCHROME
);
450 /* We don't need this anymore */
451 HeapFree(GetProcessHeap(), 0, fakeDir
);
454 WARN("Unable to get a fit entry index.\n");
459 return &dir
->idEntries
[i
-1];
464 /************* IMPLEMENTATION CORE ****************/
466 static BOOL
CURSORICON_GetCursorDataFromBMI(
467 _Inout_ CURSORDATA
* pdata
,
468 _In_
const BITMAPINFO
*pbmi
471 UINT ubmiSize
= bitmap_info_size(pbmi
, DIB_RGB_COLORS
);
472 BOOL monochrome
= is_dib_monochrome(pbmi
);
478 BITMAPINFO
* pbmiCopy
;
479 HBITMAP hbmpOld
= NULL
;
480 BOOL bResult
= FALSE
;
481 const VOID
*pvColor
, *pvMask
;
483 ibmpType
= DIB_GetBitmapInfo(&pbmi
->bmiHeader
, &width
, &height
, &bpp
, &compr
);
488 /* No compression for icons */
492 /* If no dimensions were set, use the one from the icon */
493 if(!pdata
->cx
) pdata
->cx
= width
;
494 if(!pdata
->cy
) pdata
->cy
= height
< 0 ? -height
/2 : height
/2;
496 /* Fix the hotspot coords */
497 if(pdata
->rt
== (USHORT
)((ULONG_PTR
)RT_CURSOR
))
499 if(pdata
->cx
!= width
)
500 pdata
->xHotspot
= (pdata
->xHotspot
* pdata
->cx
) / width
;
501 if(pdata
->cy
!= height
/2)
502 pdata
->yHotspot
= (pdata
->yHotspot
* pdata
->cy
* 2) / height
;
506 pdata
->xHotspot
= pdata
->cx
/2;
507 pdata
->yHotspot
= pdata
->cy
/2;
510 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
513 hdc
= CreateCompatibleDC(hdcScreen
);
520 pbmiCopy
= HeapAlloc(GetProcessHeap(), 0, max(ubmiSize
, FIELD_OFFSET(BITMAPINFO
, bmiColors
[3])));
523 RtlCopyMemory(pbmiCopy
, pbmi
, ubmiSize
);
525 /* In an icon/cursor, the BITMAPINFO holds twice the height */
526 if(pbmiCopy
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
527 ((BITMAPCOREHEADER
*)&pbmiCopy
->bmiHeader
)->bcHeight
/= 2;
529 pbmiCopy
->bmiHeader
.biHeight
/= 2;
532 pvColor
= (const char*)pbmi
+ ubmiSize
;
533 pvMask
= (const char*)pvColor
+
534 get_dib_image_size(width
, height
, bpp
);
539 /* Create the 1bpp bitmap which will contain everything */
540 pdata
->hbmColor
= NULL
;
541 pdata
->hbmMask
= CreateBitmap(pdata
->cx
, pdata
->cy
* 2, 1, 1, NULL
);
544 hbmpOld
= SelectObject(hdc
, pdata
->hbmMask
);
548 if(!StretchDIBits(hdc
, 0, pdata
->cy
, pdata
->cx
, pdata
->cy
,
550 pvColor
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
))
556 /* Create the bitmap. It has to be compatible with the screen surface */
557 pdata
->hbmColor
= CreateCompatibleBitmap(hdcScreen
, pdata
->cx
, pdata
->cy
);
560 /* Create the 1bpp mask bitmap */
561 pdata
->hbmMask
= CreateBitmap(pdata
->cx
, pdata
->cy
, 1, 1, NULL
);
564 hbmpOld
= SelectObject(hdc
, pdata
->hbmColor
);
567 if(!StretchDIBits(hdc
, 0, 0, pdata
->cx
, pdata
->cy
,
569 pvColor
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
))
571 pdata
->bpp
= GetDeviceCaps(hdcScreen
, BITSPIXEL
);
573 pdata
->hbmAlpha
= create_alpha_bitmap(pdata
->hbmColor
, pbmiCopy
, pvColor
);
575 /* Now convert the info to monochrome for the mask bits */
576 if (pbmiCopy
->bmiHeader
.biSize
!= sizeof(BITMAPCOREHEADER
))
578 RGBQUAD
*rgb
= pbmiCopy
->bmiColors
;
580 pbmiCopy
->bmiHeader
.biClrUsed
= pbmiCopy
->bmiHeader
.biClrImportant
= 2;
581 rgb
[0].rgbBlue
= rgb
[0].rgbGreen
= rgb
[0].rgbRed
= 0x00;
582 rgb
[1].rgbBlue
= rgb
[1].rgbGreen
= rgb
[1].rgbRed
= 0xff;
583 rgb
[0].rgbReserved
= rgb
[1].rgbReserved
= 0;
584 pbmiCopy
->bmiHeader
.biBitCount
= 1;
588 RGBTRIPLE
*rgb
= (RGBTRIPLE
*)(((BITMAPCOREHEADER
*)pbmiCopy
) + 1);
590 rgb
[0].rgbtBlue
= rgb
[0].rgbtGreen
= rgb
[0].rgbtRed
= 0x00;
591 rgb
[1].rgbtBlue
= rgb
[1].rgbtGreen
= rgb
[1].rgbtRed
= 0xff;
592 ((BITMAPCOREHEADER
*)&pbmiCopy
->bmiHeader
)->bcBitCount
= 1;
595 /* Set the mask bits */
596 if(!SelectObject(hdc
, pdata
->hbmMask
))
598 bResult
= StretchDIBits(hdc
, 0, 0, pdata
->cx
, pdata
->cy
,
600 pvMask
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
) != 0;
604 if(hbmpOld
) SelectObject(hdc
, hbmpOld
);
606 if(pbmiCopy
) HeapFree(GetProcessHeap(), 0, pbmiCopy
);
607 /* Clean up in case of failure */
610 if(pdata
->hbmMask
) DeleteObject(pdata
->hbmMask
);
611 if(pdata
->hbmColor
) DeleteObject(pdata
->hbmColor
);
612 if(pdata
->hbmAlpha
) DeleteObject(pdata
->hbmAlpha
);
617 static BOOL
CURSORICON_GetCursorDataFromIconInfo(
618 _Out_ CURSORDATA
* pCursorData
,
619 _In_ ICONINFO
* pIconInfo
624 ZeroMemory(pCursorData
, sizeof(*pCursorData
));
625 if(pIconInfo
->hbmColor
)
627 /* We must convert the color bitmap to screen format */
628 HDC hdcScreen
, hdcMem
;
631 /* The mask dictates its dimensions */
632 if (!GetObject(pIconInfo
->hbmMask
, sizeof(bm
), &bm
))
634 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
637 hdcMem
= CreateCompatibleDC(hdcScreen
);
643 pCursorData
->hbmColor
= CreateCompatibleBitmap(hdcScreen
, bm
.bmWidth
, bm
.bmHeight
);
645 if (!pCursorData
->hbmColor
)
650 hbmpPrev
= SelectObject(hdcMem
, pCursorData
->hbmColor
);
654 DeleteObject(pCursorData
->hbmColor
);
657 stretch_blt_icon( hdcMem
, bm
.bmWidth
, bm
.bmHeight
, pIconInfo
->hbmColor
);
658 SelectObject(hdcMem
, hbmpPrev
);
661 pCursorData
->hbmMask
= CopyImage(pIconInfo
->hbmMask
, IMAGE_BITMAP
, 0, 0, LR_MONOCHROME
);
662 if(!pCursorData
->hbmMask
)
665 /* Now, fill some information */
666 pCursorData
->rt
= (USHORT
)((ULONG_PTR
)(pIconInfo
->fIcon
? RT_ICON
: RT_CURSOR
));
667 if(pCursorData
->hbmColor
)
669 GetObject(pCursorData
->hbmColor
, sizeof(bm
), &bm
);
670 pCursorData
->bpp
= bm
.bmBitsPixel
;
671 pCursorData
->cx
= bm
.bmWidth
;
672 pCursorData
->cy
= bm
.bmHeight
;
673 if(pCursorData
->bpp
== 32)
674 pCursorData
->hbmAlpha
= create_alpha_bitmap(pCursorData
->hbmColor
, NULL
, NULL
);
678 GetObject(pCursorData
->hbmMask
, sizeof(bm
), &bm
);
679 pCursorData
->bpp
= 1;
680 pCursorData
->cx
= bm
.bmWidth
;
681 pCursorData
->cy
= bm
.bmHeight
/2;
686 pCursorData
->xHotspot
= pCursorData
->cx
/2;
687 pCursorData
->yHotspot
= pCursorData
->cy
/2;
691 pCursorData
->xHotspot
= pIconInfo
->xHotspot
;
692 pCursorData
->yHotspot
= pIconInfo
->yHotspot
;
699 #define RIFF_FOURCC( c0, c1, c2, c3 ) \
700 ( (DWORD)(BYTE)(c0) | ( (DWORD)(BYTE)(c1) << 8 ) | \
701 ( (DWORD)(BYTE)(c2) << 16 ) | ( (DWORD)(BYTE)(c3) << 24 ) )
703 #define ANI_RIFF_ID RIFF_FOURCC('R', 'I', 'F', 'F')
704 #define ANI_LIST_ID RIFF_FOURCC('L', 'I', 'S', 'T')
705 #define ANI_ACON_ID RIFF_FOURCC('A', 'C', 'O', 'N')
706 #define ANI_anih_ID RIFF_FOURCC('a', 'n', 'i', 'h')
707 #define ANI_seq__ID RIFF_FOURCC('s', 'e', 'q', ' ')
708 #define ANI_fram_ID RIFF_FOURCC('f', 'r', 'a', 'm')
709 #define ANI_rate_ID RIFF_FOURCC('r', 'a', 't', 'e')
711 #define ANI_FLAG_ICON 0x1
712 #define ANI_FLAG_SEQUENCE 0x2
714 #include <pshpack1.h>
729 const unsigned char *data
;
733 static void dump_ani_header( const ani_header
*header
)
735 TRACE(" header size: %d\n", header
->header_size
);
736 TRACE(" frames: %d\n", header
->num_frames
);
737 TRACE(" steps: %d\n", header
->num_steps
);
738 TRACE(" width: %d\n", header
->width
);
739 TRACE(" height: %d\n", header
->height
);
740 TRACE(" bpp: %d\n", header
->bpp
);
741 TRACE(" planes: %d\n", header
->num_planes
);
742 TRACE(" display rate: %d\n", header
->display_rate
);
743 TRACE(" flags: 0x%08x\n", header
->flags
);
746 /* Find an animated cursor chunk, given its type and ID */
747 static void riff_find_chunk( DWORD chunk_id
, DWORD chunk_type
, const riff_chunk_t
*parent_chunk
, riff_chunk_t
*chunk
)
749 const unsigned char *ptr
= parent_chunk
->data
;
750 const unsigned char *end
= parent_chunk
->data
+ (parent_chunk
->data_size
- (2 * sizeof(DWORD
)));
752 if (chunk_type
== ANI_LIST_ID
|| chunk_type
== ANI_RIFF_ID
) end
-= sizeof(DWORD
);
756 if ((!chunk_type
&& *(const DWORD
*)ptr
== chunk_id
)
757 || (chunk_type
&& *(const DWORD
*)ptr
== chunk_type
&& *((const DWORD
*)ptr
+ 2) == chunk_id
))
759 ptr
+= sizeof(DWORD
);
760 chunk
->data_size
= (*(const DWORD
*)ptr
+ 1) & ~1;
761 ptr
+= sizeof(DWORD
);
762 if (chunk_type
== ANI_LIST_ID
|| chunk_type
== ANI_RIFF_ID
) ptr
+= sizeof(DWORD
);
768 ptr
+= sizeof(DWORD
);
769 ptr
+= (*(const DWORD
*)ptr
+ 1) & ~1;
770 ptr
+= sizeof(DWORD
);
774 static BOOL
CURSORICON_GetCursorDataFromANI(
775 _Inout_ CURSORDATA
* pCurData
,
776 _In_
const BYTE
*pData
,
777 _In_ DWORD dwDataSize
,
782 const ani_header
*pHeader
;
783 riff_chunk_t root_chunk
= { dwDataSize
, pData
};
784 riff_chunk_t ACON_chunk
= {0};
785 riff_chunk_t anih_chunk
= {0};
786 riff_chunk_t fram_chunk
= {0};
787 riff_chunk_t rate_chunk
= {0};
788 riff_chunk_t seq_chunk
= {0};
789 const unsigned char *icon_chunk
;
790 const unsigned char *icon_data
;
792 /* Find the root chunk */
793 riff_find_chunk( ANI_ACON_ID
, ANI_RIFF_ID
, &root_chunk
, &ACON_chunk
);
794 if (!ACON_chunk
.data
)
796 ERR("Failed to get root chunk.\n");
800 /* Find the header chunk */
801 riff_find_chunk( ANI_anih_ID
, 0, &ACON_chunk
, &anih_chunk
);
802 if (!ACON_chunk
.data
)
804 ERR("Failed to get header chunk.\n");
807 pHeader
= (ani_header
*)anih_chunk
.data
;
808 dump_ani_header(pHeader
);
810 /* Set up the master data */
811 pCurData
->CURSORF_flags
|= CURSORF_ACON
;
812 pCurData
->cpcur
= pHeader
->num_frames
;
813 pCurData
->cicur
= pHeader
->num_steps
;
814 pCurData
->iicur
= pHeader
->display_rate
;
816 /* Get the sequences */
817 if (pHeader
->flags
& ANI_FLAG_SEQUENCE
)
819 riff_find_chunk( ANI_seq__ID
, 0, &ACON_chunk
, &seq_chunk
);
822 ERR("No sequence data although the flag is set!\n");
827 /* Get the frame rates */
828 riff_find_chunk( ANI_rate_ID
, 0, &ACON_chunk
, &rate_chunk
);
830 pCurData
->ajifRate
= (INT
*)rate_chunk
.data
;
832 /* Get the frames chunk */
833 riff_find_chunk( ANI_fram_ID
, ANI_LIST_ID
, &ACON_chunk
, &fram_chunk
);
834 if (!fram_chunk
.data
)
836 ERR("Failed to get icon list.\n");
839 icon_chunk
= fram_chunk
.data
;
840 icon_data
= fram_chunk
.data
+ (2 * sizeof(DWORD
));
842 if(pHeader
->num_frames
> 1)
844 /* Allocate frame descriptors, step indices and rates */
845 pCurData
->aspcur
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
846 pHeader
->num_frames
* sizeof(CURSORDATA
) + pHeader
->num_steps
* (sizeof(DWORD
) + sizeof(INT
)));
847 if(!pCurData
->aspcur
)
849 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
852 pCurData
->aicur
= (DWORD
*)(pCurData
->aspcur
+ pHeader
->num_frames
);
853 pCurData
->ajifRate
= (INT
*)(pCurData
->aicur
+ pHeader
->num_steps
);
856 for(i
=0; i
< pHeader
->num_frames
; i
++)
858 CURSORDATA
* pFrameData
;
859 const DWORD chunk_size
= *(const DWORD
*)(icon_chunk
+ sizeof(DWORD
));
860 const BITMAPINFO
* pbmi
;
862 if(pHeader
->num_frames
> 1)
863 pFrameData
= &pCurData
->aspcur
[i
];
865 pFrameData
= pCurData
;
867 pFrameData
->rt
= pCurData
->rt
;
869 if (pHeader
->flags
& ANI_FLAG_ICON
)
871 /* The chunks describe an icon file */
872 const CURSORICONFILEDIRENTRY
* pDirEntry
= get_best_icon_file_entry(
873 (const CURSORICONFILEDIR
*) icon_data
,
881 ERR("Unable to find the right file entry for frame %d.\n", i
);
884 pFrameData
->xHotspot
= pDirEntry
->xHotspot
;
885 pFrameData
->yHotspot
= pDirEntry
->yHotspot
;
886 if(!pHeader
->width
|| !pHeader
->height
)
888 pFrameData
->cx
= pDirEntry
->bWidth
;
889 pFrameData
->cy
= pDirEntry
->bHeight
;
893 pFrameData
->cx
= pHeader
->width
;
894 pFrameData
->cy
= pHeader
->height
;
896 pbmi
= (const BITMAPINFO
*) (icon_data
+ pDirEntry
->dwDIBOffset
);
900 /* The chunks just describe bitmaps */
901 pbmi
= (const BITMAPINFO
*)icon_data
;
902 pFrameData
->xHotspot
= pFrameData
->yHotspot
= 0;
905 /* Do the real work */
906 CURSORICON_GetCursorDataFromBMI(pFrameData
, pbmi
);
908 if(pHeader
->num_frames
> 1)
909 pFrameData
->CURSORF_flags
|= CURSORF_ACONFRAME
;
911 pFrameData
->CURSORF_flags
&= ~CURSORF_ACON
;
915 icon_chunk
+= chunk_size
+ (2 * sizeof(DWORD
));
916 icon_data
= icon_chunk
+ (2 * sizeof(DWORD
));
919 if(pHeader
->num_frames
<= 1)
923 CopyMemory(pCurData
->ajifRate
, rate_chunk
.data
, pHeader
->num_steps
* sizeof(INT
));
926 for(i
=0; i
< pHeader
->num_steps
; i
++)
927 pCurData
->ajifRate
[i
] = pHeader
->display_rate
;
930 if (pHeader
->flags
& ANI_FLAG_SEQUENCE
)
932 CopyMemory(pCurData
->aicur
, seq_chunk
.data
, pHeader
->num_steps
* sizeof(DWORD
));
936 for(i
=0; i
< pHeader
->num_steps
; i
++)
937 pCurData
->aicur
[i
] = i
;
943 HeapFree(GetProcessHeap(), 0, pCurData
->aspcur
);
944 ZeroMemory(pCurData
, sizeof(CURSORDATA
));
952 _In_opt_ HINSTANCE hinst
,
953 _In_ LPCWSTR lpszName
,
959 const BITMAPINFO
* pbmi
;
960 BITMAPINFO
* pbmiScaled
= NULL
;
961 BITMAPINFO
* pbmiCopy
= NULL
;
962 const VOID
* pvMapping
= NULL
;
964 HGLOBAL hgRsrc
= NULL
;
967 HDC hdcScreen
= NULL
;
969 HBITMAP hbmpOld
, hbmpRet
= NULL
;
974 /* Map the bitmap info */
975 if(fuLoad
& LR_LOADFROMFILE
)
977 const BITMAPFILEHEADER
* pbmfh
;
979 pvMapping
= map_fileW(lpszName
, NULL
);
983 if (pbmfh
->bfType
!= 0x4d42 /* 'BM' */)
985 WARN("Invalid/unsupported bitmap format!\n");
988 pbmi
= (const BITMAPINFO
*)(pbmfh
+ 1);
990 /* Get the image bits */
992 dwOffset
= pbmfh
->bfOffBits
- sizeof(BITMAPFILEHEADER
);
998 /* Caller wants an OEM bitmap */
1000 hinst
= User32Instance
;
1001 hrsrc
= FindResourceW(hinst
, lpszName
, RT_BITMAP
);
1004 hgRsrc
= LoadResource(hinst
, hrsrc
);
1007 pbmi
= LockResource(hgRsrc
);
1013 if(DIB_GetBitmapInfo(&pbmi
->bmiHeader
, &width
, &height
, &bpp
, &compr
) == -1)
1015 if((width
> 65535) || (height
> 65535))
1022 cyDesired
= -cyDesired
;
1024 iBMISize
= bitmap_info_size(pbmi
, DIB_RGB_COLORS
);
1026 /* Get a pointer to the image data */
1027 pvBits
= (char*)pbmi
+ (dwOffset
? dwOffset
: iBMISize
);
1029 /* Create a copy of the info describing the bitmap in the file */
1030 pbmiCopy
= HeapAlloc(GetProcessHeap(), 0, iBMISize
);
1033 CopyMemory(pbmiCopy
, pbmi
, iBMISize
);
1035 /* Fix it up, if needed */
1036 if(fuLoad
& (LR_LOADTRANSPARENT
| LR_LOADMAP3DCOLORS
))
1038 WORD bpp
, incr
, numColors
;
1041 COLORREF crWindow
, cr3DShadow
, cr3DFace
, cr3DLight
;
1042 BYTE pixel
= *((BYTE
*)pvBits
);
1045 if(pbmiCopy
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
1047 bpp
= ((BITMAPCOREHEADER
*)&pbmiCopy
->bmiHeader
)->bcBitCount
;
1048 numColors
= 1 << bpp
;
1049 /* BITMAPCOREINFO holds RGBTRIPLEs */
1054 bpp
= pbmiCopy
->bmiHeader
.biBitCount
;
1055 /* BITMAPINFOHEADER holds RGBQUADs */
1057 numColors
= pbmiCopy
->bmiHeader
.biClrUsed
;
1058 if(numColors
> 256) numColors
= 256;
1059 if (!numColors
&& (bpp
<= 8)) numColors
= 1 << bpp
;
1065 pbmiColors
= (char*)pbmiCopy
+ pbmiCopy
->bmiHeader
.biSize
;
1067 /* Get the relevant colors */
1068 crWindow
= GetSysColor(COLOR_WINDOW
);
1069 cr3DShadow
= GetSysColor(COLOR_3DSHADOW
);
1070 cr3DFace
= GetSysColor(COLOR_3DFACE
);
1071 cr3DLight
= GetSysColor(COLOR_3DLIGHT
);
1073 /* Fix the transparent palette entry */
1074 if(fuLoad
& LR_LOADTRANSPARENT
)
1078 case 1: pixel
>>= 7; break;
1079 case 4: pixel
>>= 4; break;
1082 FIXME("Unhandled bit depth %d.\n", bpp
);
1086 if(pixel
>= numColors
)
1088 ERR("Wrong pixel passed in.\n");
1092 /* If both flags are set, we must use COLOR_3DFACE */
1093 if(fuLoad
& LR_LOADMAP3DCOLORS
) crWindow
= cr3DFace
;
1095 /* Define the color */
1096 ptr
= (RGBTRIPLE
*)(pbmiColors
+ pixel
*incr
);
1097 ptr
->rgbtBlue
= GetBValue(crWindow
);
1098 ptr
->rgbtGreen
= GetGValue(crWindow
);
1099 ptr
->rgbtRed
= GetRValue(crWindow
);
1103 /* If we are here, then LR_LOADMAP3DCOLORS is set without LR_TRANSPARENT */
1104 for(i
= 0; i
<numColors
; i
++)
1106 ptr
= (RGBTRIPLE
*)(pbmiColors
+ i
*incr
);
1107 if((ptr
->rgbtBlue
== ptr
->rgbtRed
) && (ptr
->rgbtBlue
== ptr
->rgbtGreen
))
1109 if(ptr
->rgbtBlue
== 128)
1111 ptr
->rgbtBlue
= GetBValue(cr3DShadow
);
1112 ptr
->rgbtGreen
= GetGValue(cr3DShadow
);
1113 ptr
->rgbtRed
= GetRValue(cr3DShadow
);
1115 if(ptr
->rgbtBlue
== 192)
1117 ptr
->rgbtBlue
= GetBValue(cr3DFace
);
1118 ptr
->rgbtGreen
= GetGValue(cr3DFace
);
1119 ptr
->rgbtRed
= GetRValue(cr3DFace
);
1121 if(ptr
->rgbtBlue
== 223)
1123 ptr
->rgbtBlue
= GetBValue(cr3DLight
);
1124 ptr
->rgbtGreen
= GetGValue(cr3DLight
);
1125 ptr
->rgbtRed
= GetRValue(cr3DLight
);
1132 if(fuLoad
& LR_CREATEDIBSECTION
)
1134 /* Allocate the BMI describing the new bitmap */
1135 pbmiScaled
= HeapAlloc(GetProcessHeap(), 0, iBMISize
);
1138 CopyMemory(pbmiScaled
, pbmiCopy
, iBMISize
);
1141 if(pbmiScaled
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
1143 BITMAPCOREHEADER
* pbmch
= (BITMAPCOREHEADER
*)&pbmiScaled
->bmiHeader
;
1144 pbmch
->bcWidth
= cxDesired
;
1145 pbmch
->bcHeight
= cyDesired
;
1149 pbmiScaled
->bmiHeader
.biWidth
= cxDesired
;
1150 pbmiScaled
->bmiHeader
.biHeight
= cyDesired
;
1151 /* No compression for DIB sections */
1152 pbmiScaled
->bmiHeader
.biCompression
= BI_RGB
;
1156 /* Top-down image */
1157 if(cyDesired
< 0) cyDesired
= -cyDesired
;
1159 /* We need a device context */
1160 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
1163 hdc
= CreateCompatibleDC(hdcScreen
);
1167 /* Now create the bitmap */
1168 if(fuLoad
& LR_CREATEDIBSECTION
)
1169 hbmpRet
= CreateDIBSection(hdc
, pbmiScaled
, DIB_RGB_COLORS
, NULL
, 0, 0);
1172 if(is_dib_monochrome(pbmiCopy
) || (fuLoad
& LR_MONOCHROME
))
1173 hbmpRet
= CreateBitmap(cxDesired
, cyDesired
, 1, 1, NULL
);
1175 hbmpRet
= CreateCompatibleBitmap(hdcScreen
, cxDesired
, cyDesired
);
1181 hbmpOld
= SelectObject(hdc
, hbmpRet
);
1184 if(!StretchDIBits(hdc
, 0, 0, cxDesired
, cyDesired
,
1185 0, 0, pbmi
->bmiHeader
.biWidth
, pbmi
->bmiHeader
.biHeight
,
1186 pvBits
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
))
1188 ERR("StretchDIBits failed!.\n");
1189 SelectObject(hdc
, hbmpOld
);
1190 DeleteObject(hbmpRet
);
1195 SelectObject(hdc
, hbmpOld
);
1199 DeleteDC(hdcScreen
);
1203 HeapFree(GetProcessHeap(), 0, pbmiScaled
);
1205 HeapFree(GetProcessHeap(), 0, pbmiCopy
);
1207 UnmapViewOfFile( pvMapping
);
1209 FreeResource(hgRsrc
);
1217 CURSORICON_LoadFromFileW(
1218 _In_ LPCWSTR lpszName
,
1225 const CURSORICONFILEDIRENTRY
*entry
;
1226 const CURSORICONFILEDIR
*dir
;
1229 HANDLE hCurIcon
= NULL
;
1230 CURSORDATA cursorData
;
1232 TRACE("loading %s\n", debugstr_w( lpszName
));
1234 bits
= map_fileW( lpszName
, &filesize
);
1238 /* Check for .ani. */
1239 if (memcmp( bits
, "RIFF", 4 ) == 0)
1245 dir
= (CURSORICONFILEDIR
*) bits
;
1246 entry
= get_best_icon_file_entry(dir
, filesize
, cxDesired
, cyDesired
, bIcon
, fuLoad
);
1250 /* Fix dimensions */
1251 if(!cxDesired
) cxDesired
= entry
->bWidth
;
1252 if(!cyDesired
) cyDesired
= entry
->bHeight
;
1253 /* A bit of preparation */
1254 ZeroMemory(&cursorData
, sizeof(cursorData
));
1257 cursorData
.xHotspot
= entry
->xHotspot
;
1258 cursorData
.yHotspot
= entry
->yHotspot
;
1260 cursorData
.rt
= (USHORT
)((ULONG_PTR
)(bIcon
? RT_ICON
: RT_CURSOR
));
1263 if(!CURSORICON_GetCursorDataFromBMI(&cursorData
, (BITMAPINFO
*)&bits
[entry
->dwDIBOffset
]))
1266 hCurIcon
= NtUserxCreateEmptyCurObject(FALSE
);
1271 if(!NtUserSetCursorIconData(hCurIcon
, NULL
, NULL
, &cursorData
))
1273 NtUserDestroyCursor(hCurIcon
, TRUE
);
1278 UnmapViewOfFile(bits
);
1283 DeleteObject(cursorData
.hbmMask
);
1284 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
1285 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
1292 CURSORICON_LoadImageW(
1293 _In_opt_ HINSTANCE hinst
,
1294 _In_ LPCWSTR lpszName
,
1302 HANDLE handle
, hCurIcon
= NULL
;
1306 CURSORDATA cursorData
;
1308 UNICODE_STRING ustrRsrc
;
1309 UNICODE_STRING ustrModule
= {0, 0, NULL
};
1311 /* Fix width/height */
1312 if(fuLoad
& LR_DEFAULTSIZE
)
1314 if(!cxDesired
) cxDesired
= GetSystemMetrics(bIcon
? SM_CXICON
: SM_CXCURSOR
);
1315 if(!cyDesired
) cyDesired
= GetSystemMetrics(bIcon
? SM_CYICON
: SM_CYCURSOR
);
1318 if(fuLoad
& LR_LOADFROMFILE
)
1320 return CURSORICON_LoadFromFileW(lpszName
, cxDesired
, cyDesired
, fuLoad
, bIcon
);
1323 /* Check if caller wants OEM icons */
1325 hinst
= User32Instance
;
1327 if(fuLoad
& LR_SHARED
)
1329 DWORD size
= MAX_PATH
;
1330 FINDEXISTINGCURICONPARAM param
;
1332 TRACE("Checking for an LR_SHARED cursor/icon.\n");
1333 /* Prepare the resource name string */
1334 if(IS_INTRESOURCE(lpszName
))
1336 ustrRsrc
.Buffer
= (LPWSTR
)lpszName
;
1337 ustrRsrc
.Length
= 0;
1338 ustrRsrc
.MaximumLength
= 0;
1341 RtlInitUnicodeString(&ustrRsrc
, lpszName
);
1343 /* Prepare the module name string */
1344 ustrModule
.Buffer
= HeapAlloc(GetProcessHeap(), 0, size
*sizeof(WCHAR
));
1348 DWORD ret
= GetModuleFileNameW(hinst
, ustrModule
.Buffer
, size
);
1351 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1356 ustrModule
.Length
= ret
*sizeof(WCHAR
);
1357 ustrModule
.MaximumLength
= size
*sizeof(WCHAR
);
1361 ustrModule
.Buffer
= HeapReAlloc(GetProcessHeap(), 0, ustrModule
.Buffer
, size
*sizeof(WCHAR
));
1365 param
.bIcon
= bIcon
;
1366 param
.cx
= cxDesired
;
1367 param
.cy
= cyDesired
;
1368 hCurIcon
= NtUserFindExistingCursorIcon(&ustrModule
, &ustrRsrc
, ¶m
);
1371 /* Woohoo, got it! */
1373 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1378 /* Find resource ID */
1379 hrsrc
= FindResourceW(
1382 bIcon
? RT_GROUP_ICON
: RT_GROUP_CURSOR
);
1384 /* We let FindResource, LoadResource, etc. call SetLastError */
1388 handle
= LoadResource(hinst
, hrsrc
);
1392 dir
= LockResource(handle
);
1396 wResId
= LookupIconIdFromDirectoryEx((PBYTE
)dir
, bIcon
, cxDesired
, cyDesired
, fuLoad
);
1397 FreeResource(handle
);
1399 /* Get the relevant resource pointer */
1400 hrsrc
= FindResourceW(
1402 MAKEINTRESOURCEW(wResId
),
1403 bIcon
? RT_ICON
: RT_CURSOR
);
1407 handle
= LoadResource(hinst
, hrsrc
);
1411 bits
= LockResource(handle
);
1414 FreeResource(handle
);
1418 ZeroMemory(&cursorData
, sizeof(cursorData
));
1420 /* This is from resource */
1421 cursorData
.CURSORF_flags
= CURSORF_FROMRESOURCE
;
1423 if(dir
->idType
== 2)
1425 /* idType == 2 for cursor resources */
1426 SHORT
* ptr
= (SHORT
*)bits
;
1427 cursorData
.xHotspot
= ptr
[0];
1428 cursorData
.yHotspot
= ptr
[1];
1429 bits
+= 2*sizeof(SHORT
);
1431 cursorData
.cx
= cxDesired
;
1432 cursorData
.cy
= cyDesired
;
1433 cursorData
.rt
= (USHORT
)((ULONG_PTR
)(bIcon
? RT_ICON
: RT_CURSOR
));
1435 /* Get the bitmaps */
1436 bStatus
= CURSORICON_GetCursorDataFromBMI(
1440 FreeResource( handle
);
1445 /* Create the handle */
1446 hCurIcon
= NtUserxCreateEmptyCurObject(FALSE
);
1453 if(fuLoad
& LR_SHARED
)
1455 cursorData
.CURSORF_flags
|= CURSORF_LRSHARED
;
1456 bStatus
= NtUserSetCursorIconData(hCurIcon
, &ustrModule
, &ustrRsrc
, &cursorData
);
1459 bStatus
= NtUserSetCursorIconData(hCurIcon
, NULL
, NULL
, &cursorData
);
1463 NtUserDestroyCursor(hCurIcon
, TRUE
);
1468 if(ustrModule
.Buffer
)
1469 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1473 if(ustrModule
.Buffer
)
1474 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1475 DeleteObject(cursorData
.hbmMask
);
1476 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
1477 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
1496 objSize
= GetObjectW( hnd
, sizeof(ds
), &ds
);
1497 if (!objSize
) return 0;
1498 if ((desiredx
< 0) || (desiredy
< 0)) return 0;
1500 if (flags
& LR_COPYFROMRESOURCE
)
1502 FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
1505 if (flags
& LR_COPYRETURNORG
)
1507 FIXME("The flag LR_COPYRETURNORG is not implemented for bitmaps\n");
1510 if (desiredx
== 0) desiredx
= ds
.dsBm
.bmWidth
;
1511 if (desiredy
== 0) desiredy
= ds
.dsBm
.bmHeight
;
1513 /* Allocate memory for a BITMAPINFOHEADER structure and a
1514 color table. The maximum number of colors in a color table
1515 is 256 which corresponds to a bitmap with depth 8.
1516 Bitmaps with higher depths don't have color tables. */
1517 bi
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
));
1520 bi
->bmiHeader
.biSize
= sizeof(bi
->bmiHeader
);
1521 bi
->bmiHeader
.biPlanes
= ds
.dsBm
.bmPlanes
;
1522 bi
->bmiHeader
.biBitCount
= ds
.dsBm
.bmBitsPixel
;
1523 bi
->bmiHeader
.biCompression
= BI_RGB
;
1525 if (flags
& LR_CREATEDIBSECTION
)
1527 /* Create a DIB section. LR_MONOCHROME is ignored */
1529 HDC dc
= CreateCompatibleDC(NULL
);
1531 if (objSize
== sizeof(DIBSECTION
))
1533 /* The source bitmap is a DIB.
1534 Get its attributes to create an exact copy */
1535 memcpy(bi
, &ds
.dsBmih
, sizeof(BITMAPINFOHEADER
));
1538 bi
->bmiHeader
.biWidth
= desiredx
;
1539 bi
->bmiHeader
.biHeight
= desiredy
;
1541 /* Get the color table or the color masks */
1542 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
1544 res
= CreateDIBSection(dc
, bi
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
1549 /* Create a device-dependent bitmap */
1551 BOOL monochrome
= (flags
& LR_MONOCHROME
);
1553 if (objSize
== sizeof(DIBSECTION
))
1555 /* The source bitmap is a DIB section.
1556 Get its attributes */
1557 HDC dc
= CreateCompatibleDC(NULL
);
1558 bi
->bmiHeader
.biWidth
= ds
.dsBm
.bmWidth
;
1559 bi
->bmiHeader
.biHeight
= ds
.dsBm
.bmHeight
;
1560 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
1563 if (!monochrome
&& ds
.dsBm
.bmBitsPixel
== 1)
1565 /* Look if the colors of the DIB are black and white */
1568 (bi
->bmiColors
[0].rgbRed
== 0xff
1569 && bi
->bmiColors
[0].rgbGreen
== 0xff
1570 && bi
->bmiColors
[0].rgbBlue
== 0xff
1571 && bi
->bmiColors
[0].rgbReserved
== 0
1572 && bi
->bmiColors
[1].rgbRed
== 0
1573 && bi
->bmiColors
[1].rgbGreen
== 0
1574 && bi
->bmiColors
[1].rgbBlue
== 0
1575 && bi
->bmiColors
[1].rgbReserved
== 0)
1577 (bi
->bmiColors
[0].rgbRed
== 0
1578 && bi
->bmiColors
[0].rgbGreen
== 0
1579 && bi
->bmiColors
[0].rgbBlue
== 0
1580 && bi
->bmiColors
[0].rgbReserved
== 0
1581 && bi
->bmiColors
[1].rgbRed
== 0xff
1582 && bi
->bmiColors
[1].rgbGreen
== 0xff
1583 && bi
->bmiColors
[1].rgbBlue
== 0xff
1584 && bi
->bmiColors
[1].rgbReserved
== 0);
1587 else if (!monochrome
)
1589 monochrome
= ds
.dsBm
.bmBitsPixel
== 1;
1594 res
= CreateBitmap(desiredx
, desiredy
, 1, 1, NULL
);
1598 HDC screenDC
= GetDC(NULL
);
1599 res
= CreateCompatibleBitmap(screenDC
, desiredx
, desiredy
);
1600 ReleaseDC(NULL
, screenDC
);
1606 /* Only copy the bitmap if it's a DIB section or if it's
1607 compatible to the screen */
1610 if (objSize
== sizeof(DIBSECTION
))
1612 copyContents
= TRUE
;
1616 HDC screenDC
= GetDC(NULL
);
1617 int screen_depth
= GetDeviceCaps(screenDC
, BITSPIXEL
);
1618 ReleaseDC(NULL
, screenDC
);
1620 copyContents
= (ds
.dsBm
.bmBitsPixel
== 1 || ds
.dsBm
.bmBitsPixel
== screen_depth
);
1625 /* The source bitmap may already be selected in a device context,
1626 use GetDIBits/StretchDIBits and not StretchBlt */
1631 dc
= CreateCompatibleDC(NULL
);
1633 bi
->bmiHeader
.biWidth
= ds
.dsBm
.bmWidth
;
1634 bi
->bmiHeader
.biHeight
= ds
.dsBm
.bmHeight
;
1635 bi
->bmiHeader
.biSizeImage
= 0;
1636 bi
->bmiHeader
.biClrUsed
= 0;
1637 bi
->bmiHeader
.biClrImportant
= 0;
1639 /* Fill in biSizeImage */
1640 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
1641 bits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, bi
->bmiHeader
.biSizeImage
);
1647 /* Get the image bits of the source bitmap */
1648 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, bits
, bi
, DIB_RGB_COLORS
);
1650 /* Copy it to the destination bitmap */
1651 oldBmp
= SelectObject(dc
, res
);
1652 StretchDIBits(dc
, 0, 0, desiredx
, desiredy
,
1653 0, 0, ds
.dsBm
.bmWidth
, ds
.dsBm
.bmHeight
,
1654 bits
, bi
, DIB_RGB_COLORS
, SRCCOPY
);
1655 SelectObject(dc
, oldBmp
);
1657 HeapFree(GetProcessHeap(), 0, bits
);
1663 if (flags
& LR_COPYDELETEORG
)
1668 HeapFree(GetProcessHeap(), 0, bi
);
1674 CURSORICON_CopyImage(
1685 if(fuFlags
& LR_COPYFROMRESOURCE
)
1687 /* Get the icon module/resource names */
1688 UNICODE_STRING ustrModule
;
1689 UNICODE_STRING ustrRsrc
;
1693 ustrModule
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
1694 ustrRsrc
.MaximumLength
= 256;
1696 ustrModule
.Buffer
= HeapAlloc(GetProcessHeap(), 0, ustrModule
.MaximumLength
);
1697 if(!ustrModule
.Buffer
)
1699 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1702 /* Keep track of the buffer for the resource, NtUserGetIconInfo might overwrite it */
1703 pvBuf
= HeapAlloc(GetProcessHeap(), 0, ustrRsrc
.MaximumLength
);
1706 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1707 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1710 ustrRsrc
.Buffer
= pvBuf
;
1714 if (!NtUserGetIconInfo(hicon
, NULL
, &ustrModule
, &ustrRsrc
, NULL
, FALSE
))
1716 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1717 HeapFree(GetProcessHeap(), 0, pvBuf
);
1721 if (ustrModule
.Length
&& (ustrRsrc
.Length
|| IS_INTRESOURCE(ustrRsrc
.Buffer
)))
1723 /* Buffers were big enough */
1727 /* Find which buffer were too small */
1728 if (!ustrModule
.Length
)
1731 ustrModule
.MaximumLength
*= 2;
1732 newBuffer
= HeapReAlloc(GetProcessHeap(), 0, ustrModule
.Buffer
, ustrModule
.MaximumLength
);
1733 if(!ustrModule
.Buffer
)
1735 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1738 ustrModule
.Buffer
= newBuffer
;
1741 if (!ustrRsrc
.Length
)
1743 ustrRsrc
.MaximumLength
*= 2;
1744 pvBuf
= HeapReAlloc(GetProcessHeap(), 0, ustrRsrc
.Buffer
, ustrRsrc
.MaximumLength
);
1747 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1750 ustrRsrc
.Buffer
= pvBuf
;
1754 /* NULL-terminate our strings */
1755 ustrModule
.Buffer
[ustrModule
.Length
/sizeof(WCHAR
)] = 0;
1756 if(!IS_INTRESOURCE(ustrRsrc
.Buffer
))
1757 ustrRsrc
.Buffer
[ustrRsrc
.Length
/sizeof(WCHAR
)] = 0;
1759 /* Get the module handle */
1760 if(!GetModuleHandleExW(0, ustrModule
.Buffer
, &hModule
))
1762 /* This should never happen */
1763 ERR("Invalid handle?.\n");
1764 SetLastError(ERROR_INVALID_PARAMETER
);
1768 /* Call the relevant function */
1769 ret
= CURSORICON_LoadImageW(hModule
, ustrRsrc
.Buffer
, cxDesired
, cyDesired
, fuFlags
& LR_DEFAULTSIZE
, bIcon
);
1771 FreeLibrary(hModule
);
1773 /* If we're here, that means that the passed icon is shared. Don't destroy it, even if LR_COPYDELETEORG is specified */
1775 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1776 HeapFree(GetProcessHeap(), 0, pvBuf
);
1778 TRACE("Returning 0x%08x.\n", ret
);
1783 /* This is a regular copy */
1784 if(fuFlags
& ~LR_COPYDELETEORG
)
1785 FIXME("Unimplemented flags: 0x%08x\n", fuFlags
);
1787 if(!GetIconInfo(hicon
, &ii
))
1789 ERR("GetIconInfo failed.\n");
1793 ret
= CreateIconIndirect(&ii
);
1795 DeleteObject(ii
.hbmMask
);
1796 if(ii
.hbmColor
) DeleteObject(ii
.hbmColor
);
1798 if(ret
&& (fuFlags
& LR_COPYDELETEORG
))
1805 User32CallCopyImageFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
1807 PCOPYIMAGE_CALLBACK_ARGUMENTS Common
;
1809 Common
= (PCOPYIMAGE_CALLBACK_ARGUMENTS
) Arguments
;
1811 Result
= CopyImage(Common
->hImage
,
1817 return ZwCallbackReturn(&Result
, sizeof(HANDLE
), STATUS_SUCCESS
);
1821 /************* PUBLIC FUNCTIONS *******************/
1823 HANDLE WINAPI
CopyImage(
1831 TRACE("hImage=%p, uType=%u, cxDesired=%d, cyDesired=%d, fuFlags=%x\n",
1832 hImage
, uType
, cxDesired
, cyDesired
, fuFlags
);
1836 return BITMAP_CopyImage(hImage
, cxDesired
, cyDesired
, fuFlags
);
1839 return CURSORICON_CopyImage(hImage
, uType
== IMAGE_ICON
, cxDesired
, cyDesired
, fuFlags
);
1841 SetLastError(ERROR_INVALID_PARAMETER
);
1847 HICON WINAPI
CopyIcon(
1851 return CURSORICON_CopyImage(hIcon
, FALSE
, 0, 0, 0);
1854 BOOL WINAPI
DrawIcon(
1861 return DrawIconEx(hDC
, X
, Y
, hIcon
, 0, 0, 0, NULL
, DI_NORMAL
| DI_COMPAT
| DI_DEFAULTSIZE
);
1864 BOOL WINAPI
DrawIconEx(
1871 _In_ UINT istepIfAniCur
,
1872 _In_opt_ HBRUSH hbrFlickerFreeDraw
,
1876 return NtUserDrawIconEx(hdc
, xLeft
, yTop
, hIcon
, cxWidth
, cyWidth
,
1877 istepIfAniCur
, hbrFlickerFreeDraw
, diFlags
,
1881 BOOL WINAPI
GetIconInfo(
1883 _Out_ PICONINFO piconinfo
1886 return NtUserGetIconInfo(hIcon
, piconinfo
, NULL
, NULL
, NULL
, FALSE
);
1889 BOOL WINAPI
DestroyIcon(
1893 return NtUserDestroyCursor(hIcon
, FALSE
);
1896 HICON WINAPI
LoadIconA(
1897 _In_opt_ HINSTANCE hInstance
,
1898 _In_ LPCSTR lpIconName
1901 TRACE("%p, %s\n", hInstance
, debugstr_a(lpIconName
));
1903 return LoadImageA(hInstance
,
1908 LR_SHARED
| LR_DEFAULTSIZE
);
1911 HICON WINAPI
LoadIconW(
1912 _In_opt_ HINSTANCE hInstance
,
1913 _In_ LPCWSTR lpIconName
1916 TRACE("%p, %s\n", hInstance
, debugstr_w(lpIconName
));
1918 return LoadImageW(hInstance
,
1923 LR_SHARED
| LR_DEFAULTSIZE
);
1926 HCURSOR WINAPI
LoadCursorA(
1927 _In_opt_ HINSTANCE hInstance
,
1928 _In_ LPCSTR lpCursorName
1931 TRACE("%p, %s\n", hInstance
, debugstr_a(lpCursorName
));
1933 return LoadImageA(hInstance
,
1938 LR_SHARED
| LR_DEFAULTSIZE
);
1941 HCURSOR WINAPI
LoadCursorW(
1942 _In_opt_ HINSTANCE hInstance
,
1943 _In_ LPCWSTR lpCursorName
1946 TRACE("%p, %s\n", hInstance
, debugstr_w(lpCursorName
));
1948 return LoadImageW(hInstance
,
1953 LR_SHARED
| LR_DEFAULTSIZE
);
1956 HCURSOR WINAPI
LoadCursorFromFileA(
1957 _In_ LPCSTR lpFileName
1960 TRACE("%s\n", debugstr_a(lpFileName
));
1962 return LoadImageA(NULL
,
1967 LR_LOADFROMFILE
| LR_DEFAULTSIZE
);
1970 HCURSOR WINAPI
LoadCursorFromFileW(
1971 _In_ LPCWSTR lpFileName
1974 TRACE("%s\n", debugstr_w(lpFileName
));
1976 return LoadImageW(NULL
,
1981 LR_LOADFROMFILE
| LR_DEFAULTSIZE
);
1984 HBITMAP WINAPI
LoadBitmapA(
1985 _In_opt_ HINSTANCE hInstance
,
1986 _In_ LPCSTR lpBitmapName
1989 TRACE("%p, %s\n", hInstance
, debugstr_a(lpBitmapName
));
1991 return LoadImageA(hInstance
,
1999 HBITMAP WINAPI
LoadBitmapW(
2000 _In_opt_ HINSTANCE hInstance
,
2001 _In_ LPCWSTR lpBitmapName
2004 TRACE("%p, %s\n", hInstance
, debugstr_w(lpBitmapName
));
2006 return LoadImageW(hInstance
,
2014 HANDLE WINAPI
LoadImageA(
2015 _In_opt_ HINSTANCE hinst
,
2016 _In_ LPCSTR lpszName
,
2027 if (IS_INTRESOURCE(lpszName
))
2028 return LoadImageW(hinst
, (LPCWSTR
)lpszName
, uType
, cxDesired
, cyDesired
, fuLoad
);
2030 len
= MultiByteToWideChar( CP_ACP
, 0, lpszName
, -1, NULL
, 0 );
2031 u_name
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
2032 MultiByteToWideChar( CP_ACP
, 0, lpszName
, -1, u_name
, len
);
2034 res
= LoadImageW(hinst
, u_name
, uType
, cxDesired
, cyDesired
, fuLoad
);
2035 HeapFree(GetProcessHeap(), 0, u_name
);
2039 HANDLE WINAPI
LoadImageW(
2040 _In_opt_ HINSTANCE hinst
,
2041 _In_ LPCWSTR lpszName
,
2048 TRACE("hinst 0x%p, name %s, uType 0x%08x, cxDesired %d, cyDesired %d, fuLoad 0x%08x.\n",
2049 hinst
, debugstr_w(lpszName
), uType
, cxDesired
, cyDesired
, fuLoad
);
2050 /* Redirect to each implementation */
2054 return BITMAP_LoadImageW(hinst
, lpszName
, cxDesired
, cyDesired
, fuLoad
);
2057 return CURSORICON_LoadImageW(hinst
, lpszName
, cxDesired
, cyDesired
, fuLoad
, uType
== IMAGE_ICON
);
2059 SetLastError(ERROR_INVALID_PARAMETER
);
2065 int WINAPI
LookupIconIdFromDirectory(
2066 _In_ PBYTE presbits
,
2070 return LookupIconIdFromDirectoryEx( presbits
, fIcon
,
2071 fIcon
? GetSystemMetrics(SM_CXICON
) : GetSystemMetrics(SM_CXCURSOR
),
2072 fIcon
? GetSystemMetrics(SM_CYICON
) : GetSystemMetrics(SM_CYCURSOR
), fIcon
? 0 : LR_MONOCHROME
);
2075 int WINAPI
LookupIconIdFromDirectoryEx(
2076 _In_ PBYTE presbits
,
2084 CURSORICONDIR
* dir
= (CURSORICONDIR
*)presbits
;
2085 CURSORICONDIRENTRY
* entry
;
2086 int i
, numMatch
= 0, iIndex
= -1;
2087 WORD width
, height
, BitCount
= 0;
2088 BOOL notPaletted
= FALSE
;
2089 ULONG bestScore
= 0xFFFFFFFF, score
;
2091 TRACE("%p, %x, %i, %i, %x.\n", presbits
, fIcon
, cxDesired
, cyDesired
, Flags
);
2093 if(!(dir
&& !dir
->idReserved
&& (dir
->idType
& 3)))
2095 WARN("Invalid resource.\n");
2099 if(Flags
& LR_MONOCHROME
)
2104 icScreen
= CreateICW(DISPLAYW
, NULL
, NULL
, NULL
);
2108 bppDesired
= GetDeviceCaps(icScreen
, BITSPIXEL
);
2113 cxDesired
= Flags
& LR_DEFAULTSIZE
? GetSystemMetrics(fIcon
? SM_CXICON
: SM_CXCURSOR
) : 256;
2115 cyDesired
= Flags
& LR_DEFAULTSIZE
? GetSystemMetrics(fIcon
? SM_CYICON
: SM_CYCURSOR
) : 256;
2117 /* Find the best match for the desired size */
2118 for(i
= 0; i
< dir
->idCount
; i
++)
2120 entry
= &dir
->idEntries
[i
];
2121 width
= fIcon
? entry
->ResInfo
.icon
.bWidth
: entry
->ResInfo
.cursor
.wWidth
;
2122 /* Height is twice as big in cursor resources */
2123 height
= fIcon
? entry
->ResInfo
.icon
.bHeight
: entry
->ResInfo
.cursor
.wHeight
/2;
2124 /* 0 represents 256 */
2125 if(!width
) width
= 256;
2126 if(!height
) height
= 256;
2127 /* Calculate the "score" (lower is better) */
2128 score
= 2*(abs(width
- cxDesired
) + abs(height
- cyDesired
));
2129 if( score
> bestScore
)
2131 /* Bigger than requested lowers the score */
2132 if(width
> cxDesired
)
2133 score
-= width
- cxDesired
;
2134 if(height
> cyDesired
)
2135 score
-= height
- cyDesired
;
2136 if(score
> bestScore
)
2138 if(score
== bestScore
)
2140 if(entry
->wBitCount
> BitCount
)
2141 BitCount
= entry
->wBitCount
;
2148 BitCount
= entry
->wBitCount
;
2153 /* Only one entry fits the asked dimensions */
2154 return dir
->idEntries
[iIndex
].wResId
;
2157 /* Avoid paletted icons on non-paletted device */
2158 if (bppDesired
> 8 && BitCount
> 8)
2163 /* Now find the entry with the best depth */
2164 for(i
= 0; i
< dir
->idCount
; i
++)
2166 entry
= &dir
->idEntries
[i
];
2167 width
= fIcon
? entry
->ResInfo
.icon
.bWidth
: entry
->ResInfo
.cursor
.wWidth
;
2168 height
= fIcon
? entry
->ResInfo
.icon
.bHeight
: entry
->ResInfo
.cursor
.wHeight
/2;
2169 /* 0 represents 256 */
2170 if(!width
) width
= 256;
2171 if(!height
) height
= 256;
2172 /* Check if this is the best match we had */
2173 score
= 2*(abs(width
- cxDesired
) + abs(height
- cyDesired
));
2174 if(width
> cxDesired
)
2175 score
-= width
- cxDesired
;
2176 if(height
> cyDesired
)
2177 score
-= height
- cyDesired
;
2178 if(score
!= bestScore
)
2181 if(entry
->wBitCount
== bppDesired
)
2182 return entry
->wResId
;
2183 /* We take the highest possible but smaller than the display depth */
2184 if((entry
->wBitCount
> BitCount
) && (entry
->wBitCount
< bppDesired
))
2186 /* Avoid paletted icons on non paletted devices */
2187 if ((entry
->wBitCount
<= 8) && notPaletted
)
2190 BitCount
= entry
->wBitCount
;
2195 return dir
->idEntries
[iIndex
].wResId
;
2197 /* No inferior or equal depth available. Get the smallest bigger one */
2200 for(i
= 0; i
< dir
->idCount
; i
++)
2202 entry
= &dir
->idEntries
[i
];
2203 width
= fIcon
? entry
->ResInfo
.icon
.bWidth
: entry
->ResInfo
.cursor
.wWidth
;
2204 height
= fIcon
? entry
->ResInfo
.icon
.bHeight
: entry
->ResInfo
.cursor
.wHeight
/2;
2205 /* 0 represents 256 */
2206 if(!width
) width
= 256;
2207 if(!height
) height
= 256;
2208 /* Check if this is the best match we had */
2209 score
= 2*(abs(width
- cxDesired
) + abs(height
- cyDesired
));
2210 if(width
> cxDesired
)
2211 score
-= width
- cxDesired
;
2212 if(height
> cyDesired
)
2213 score
-= height
- cyDesired
;
2214 if(score
!= bestScore
)
2216 /* Check the bit depth */
2217 if(entry
->wBitCount
< BitCount
)
2219 if((entry
->wBitCount
<= 8) && notPaletted
)
2222 BitCount
= entry
->wBitCount
;
2226 return dir
->idEntries
[iIndex
].wResId
;
2229 HICON WINAPI
CreateIcon(
2230 _In_opt_ HINSTANCE hInstance
,
2234 _In_ BYTE cBitsPixel
,
2235 _In_
const BYTE
*lpbANDbits
,
2236 _In_
const BYTE
*lpbXORbits
2242 TRACE_(icon
)("%dx%d, planes %d, bpp %d, xor %p, and %p\n",
2243 nWidth
, nHeight
, cPlanes
, cBitsPixel
, lpbXORbits
, lpbANDbits
);
2246 iinfo
.xHotspot
= nWidth
/ 2;
2247 iinfo
.yHotspot
= nHeight
/ 2;
2248 if (cPlanes
* cBitsPixel
> 1)
2250 iinfo
.hbmColor
= CreateBitmap( nWidth
, nHeight
, cPlanes
, cBitsPixel
, lpbXORbits
);
2251 iinfo
.hbmMask
= CreateBitmap( nWidth
, nHeight
, 1, 1, lpbANDbits
);
2255 iinfo
.hbmMask
= CreateBitmap( nWidth
, nHeight
* 2, 1, 1, lpbANDbits
);
2256 iinfo
.hbmColor
= NULL
;
2259 hIcon
= CreateIconIndirect( &iinfo
);
2261 DeleteObject( iinfo
.hbmMask
);
2262 if (iinfo
.hbmColor
) DeleteObject( iinfo
.hbmColor
);
2267 HICON WINAPI
CreateIconFromResource(
2268 _In_ PBYTE presbits
,
2269 _In_ DWORD dwResSize
,
2274 return CreateIconFromResourceEx( presbits
, dwResSize
, fIcon
, dwVer
, 0, 0, LR_DEFAULTSIZE
| LR_SHARED
);
2277 HICON WINAPI
CreateIconFromResourceEx(
2278 _In_ PBYTE pbIconBits
,
2279 _In_ DWORD cbIconBits
,
2281 _In_ DWORD dwVersion
,
2287 CURSORDATA cursorData
;
2291 TRACE("%p, %lu, %lu, %lu, %i, %i, %lu.\n", pbIconBits
, cbIconBits
, fIcon
, dwVersion
, cxDesired
, cyDesired
, uFlags
);
2293 if(uFlags
& LR_DEFAULTSIZE
)
2295 if(!cxDesired
) cxDesired
= GetSystemMetrics(fIcon
? SM_CXICON
: SM_CXCURSOR
);
2296 if(!cyDesired
) cyDesired
= GetSystemMetrics(fIcon
? SM_CYICON
: SM_CYCURSOR
);
2299 ZeroMemory(&cursorData
, sizeof(cursorData
));
2300 cursorData
.cx
= cxDesired
;
2301 cursorData
.cy
= cyDesired
;
2302 cursorData
.rt
= (USHORT
)((ULONG_PTR
)(fIcon
? RT_ICON
: RT_CURSOR
));
2304 /* Convert to win32k-ready data */
2305 if(!memcmp(pbIconBits
, "RIFF", 4))
2307 if(!CURSORICON_GetCursorDataFromANI(&cursorData
, pbIconBits
, cbIconBits
, uFlags
))
2309 ERR("Could not get cursor data from .ani.\n");
2312 isAnimated
= !!(cursorData
.CURSORF_flags
& CURSORF_ACON
);
2316 /* It is possible to pass Icon Directories to this API */
2317 int wResId
= LookupIconIdFromDirectoryEx(pbIconBits
, fIcon
, cxDesired
, cyDesired
, uFlags
);
2318 HANDLE ResHandle
= NULL
;
2323 CURSORICONDIR
* pCurIconDir
= (CURSORICONDIR
*)pbIconBits
;
2325 TRACE("Pointer points to a directory structure.\n");
2327 /* So this is a pointer to an icon directory structure. Find the module */
2328 if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
| GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
,
2329 (LPCWSTR
)pbIconBits
,
2335 /* Check we were given the right type of resource */
2336 if((fIcon
&& pCurIconDir
->idType
== 2) || (!fIcon
&& pCurIconDir
->idType
== 1))
2338 WARN("Got a %s directory pointer, but called for a %s", fIcon
? "cursor" : "icon", fIcon
? "icon" : "cursor");
2342 /* Get the relevant resource pointer */
2343 hrsrc
= FindResourceW(
2345 MAKEINTRESOURCEW(wResId
),
2346 fIcon
? RT_ICON
: RT_CURSOR
);
2350 ResHandle
= LoadResource(hinst
, hrsrc
);
2354 pbIconBits
= LockResource(ResHandle
);
2357 FreeResource(ResHandle
);
2363 WORD
* pt
= (WORD
*)pbIconBits
;
2364 cursorData
.xHotspot
= *pt
++;
2365 cursorData
.yHotspot
= *pt
++;
2366 pbIconBits
= (PBYTE
)pt
;
2369 if (!CURSORICON_GetCursorDataFromBMI(&cursorData
, (BITMAPINFO
*)pbIconBits
))
2371 ERR("Couldn't fill the CURSORDATA structure.\n");
2373 FreeResource(ResHandle
);
2377 FreeResource(ResHandle
);
2381 if (uFlags
& LR_SHARED
)
2382 cursorData
.CURSORF_flags
|= CURSORF_LRSHARED
;
2384 hIcon
= NtUserxCreateEmptyCurObject(isAnimated
);
2388 if(!NtUserSetCursorIconData(hIcon
, NULL
, NULL
, &cursorData
))
2390 ERR("NtUserSetCursorIconData failed.\n");
2391 NtUserDestroyCursor(hIcon
, TRUE
);
2396 HeapFree(GetProcessHeap(), 0, cursorData
.aspcur
);
2403 HeapFree(GetProcessHeap(), 0, cursorData
.aspcur
);
2404 DeleteObject(cursorData
.hbmMask
);
2405 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
2406 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
2411 HICON WINAPI
CreateIconIndirect(
2412 _In_ PICONINFO piconinfo
2415 /* As simple as creating a handle, and let win32k deal with the bitmaps */
2417 CURSORDATA cursorData
;
2419 TRACE("%p.\n", piconinfo
);
2421 ZeroMemory(&cursorData
, sizeof(cursorData
));
2423 if(!CURSORICON_GetCursorDataFromIconInfo(&cursorData
, piconinfo
))
2426 hiconRet
= NtUserxCreateEmptyCurObject(FALSE
);
2430 if(!NtUserSetCursorIconData(hiconRet
, NULL
, NULL
, &cursorData
))
2432 NtUserDestroyCursor(hiconRet
, FALSE
);
2436 TRACE("Returning 0x%08x.\n", hiconRet
);
2442 DeleteObject(cursorData
.hbmMask
);
2443 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
2444 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
2449 HCURSOR WINAPI
CreateCursor(
2450 _In_opt_ HINSTANCE hInst
,
2455 _In_
const VOID
*pvANDPlane
,
2456 _In_
const VOID
*pvXORPlane
2462 TRACE_(cursor
)("%dx%d spot=%d,%d xor=%p and=%p\n",
2463 nWidth
, nHeight
, xHotSpot
, yHotSpot
, pvXORPlane
, pvANDPlane
);
2466 info
.xHotspot
= xHotSpot
;
2467 info
.yHotspot
= yHotSpot
;
2468 info
.hbmMask
= CreateBitmap( nWidth
, nHeight
, 1, 1, pvANDPlane
);
2469 info
.hbmColor
= CreateBitmap( nWidth
, nHeight
, 1, 1, pvXORPlane
);
2470 hCursor
= CreateIconIndirect( &info
);
2471 DeleteObject( info
.hbmMask
);
2472 DeleteObject( info
.hbmColor
);
2476 BOOL WINAPI
SetSystemCursor(
2485 BOOL WINAPI
SetCursorPos(
2490 return NtUserxSetCursorPos(X
,Y
);
2493 BOOL WINAPI
GetCursorPos(
2494 _Out_ LPPOINT lpPoint
2497 return NtUserxGetCursorPos(lpPoint
);
2500 int WINAPI
ShowCursor(
2504 return NtUserxShowCursor(bShow
);
2507 HCURSOR WINAPI
GetCursor(void)
2509 return (HCURSOR
)NtUserGetThreadState(THREADSTATE_GETCURSOR
);
2512 BOOL WINAPI
DestroyCursor(
2513 _In_ HCURSOR hCursor
2516 return NtUserDestroyCursor(hCursor
, FALSE
);
2521 GetCursorFrameInfo(HCURSOR hCursor
, DWORD reserved
, DWORD istep
, PINT rate_jiffies
, DWORD
*num_steps
)
2523 return NtUserGetCursorFrameInfo(hCursor
, istep
, rate_jiffies
, num_steps
);