2 * PROJECT: ReactOS user32.dll
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: win32ss/user/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 VOID
LoadSystemCursors(VOID
)
25 if (!gpsi
->hIconSmWindows
)
27 ERR("Loading System Cursors\n");
28 NtUserSetSystemCursor(LoadImageW( 0, IDC_ARROW
, IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
), OCR_NORMAL
);
29 NtUserSetSystemCursor(LoadImageW( 0, IDC_IBEAM
, IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
), OCR_IBEAM
);
30 NtUserSetSystemCursor(LoadImageW( 0, IDC_WAIT
, IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
), OCR_WAIT
);
31 NtUserSetSystemCursor(LoadImageW( 0, IDC_CROSS
, IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
), OCR_CROSS
);
32 NtUserSetSystemCursor(LoadImageW( 0, IDC_UPARROW
, IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
), OCR_UP
);
33 NtUserSetSystemCursor(LoadImageW( 0, IDC_ICON
, IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
), OCR_ICON
);
34 NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZE
, IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
), OCR_SIZE
);
35 NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZENWSE
, IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
), OCR_SIZENWSE
);
36 NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZENESW
, IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
), OCR_SIZENESW
);
37 NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZEWE
, IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
), OCR_SIZEWE
);
38 NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZENS
, IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
), OCR_SIZENS
);
39 NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZEALL
, IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
), OCR_SIZEALL
);
40 NtUserSetSystemCursor(LoadImageW( 0, IDC_NO
, IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
), OCR_NO
);
41 NtUserSetSystemCursor(LoadImageW( 0, IDC_HAND
, IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
), OCR_HAND
);
42 NtUserSetSystemCursor(LoadImageW( 0, IDC_APPSTARTING
, IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
), OCR_APPSTARTING
);
43 NtUserSetSystemCursor(LoadImageW( 0, IDC_HELP
, IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
), OCR_HELP
);
47 /* This callback routine is called directly after switching to gui mode */
50 User32SetupDefaultCursors(PVOID Arguments
,
53 BOOL
*DefaultCursor
= (BOOL
*)Arguments
;
56 /* Load system cursors first */
61 /* set default cursor */
62 hCursor
= LoadCursorW(0, IDC_ARROW
);
67 /* FIXME load system cursor scheme */
69 hCursor
= LoadCursorW(0, IDC_ARROW
);
73 return(ZwCallbackReturn(&hCursor
, sizeof(HCURSOR
), STATUS_SUCCESS
));
76 BOOL
get_icon_size(HICON hIcon
, SIZE
*size
)
78 return NtUserGetIconSize(hIcon
, 0, &size
->cx
, &size
->cy
);
81 HCURSOR
CursorIconToCursor(HICON hIcon
, BOOL SemiTransparent
)
87 /************* IMPLEMENTATION HELPERS ******************/
89 static const WCHAR DISPLAYW
[] = L
"DISPLAY";
91 static void *map_fileW( LPCWSTR name
, LPDWORD filesize
)
93 HANDLE hFile
, hMapping
;
96 hFile
= CreateFileW( name
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
97 OPEN_EXISTING
, FILE_FLAG_RANDOM_ACCESS
, 0 );
98 if (hFile
!= INVALID_HANDLE_VALUE
)
100 hMapping
= CreateFileMappingW( hFile
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
103 ptr
= MapViewOfFile( hMapping
, FILE_MAP_READ
, 0, 0, 0 );
104 CloseHandle( hMapping
);
106 *filesize
= GetFileSize( hFile
, NULL
);
108 CloseHandle( hFile
);
113 static int get_dib_image_size( int width
, int height
, int depth
)
115 return (((width
* depth
+ 31) / 8) & ~3) * abs( height
);
118 static BOOL
is_dib_monochrome( const BITMAPINFO
* info
)
120 if (info
->bmiHeader
.biBitCount
!= 1) return FALSE
;
122 if (info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
124 const RGBTRIPLE
*rgb
= ((const BITMAPCOREINFO
*)info
)->bmciColors
;
126 /* Check if the first color is black */
127 if ((rgb
->rgbtRed
== 0) && (rgb
->rgbtGreen
== 0) && (rgb
->rgbtBlue
== 0))
131 /* Check if the second color is white */
132 return ((rgb
->rgbtRed
== 0xff) && (rgb
->rgbtGreen
== 0xff)
133 && (rgb
->rgbtBlue
== 0xff));
137 else /* assume BITMAPINFOHEADER */
139 const RGBQUAD
*rgb
= info
->bmiColors
;
141 /* Check if the first color is black */
142 if ((rgb
->rgbRed
== 0) && (rgb
->rgbGreen
== 0) &&
143 (rgb
->rgbBlue
== 0) && (rgb
->rgbReserved
== 0))
147 /* Check if the second color is white */
148 return ((rgb
->rgbRed
== 0xff) && (rgb
->rgbGreen
== 0xff)
149 && (rgb
->rgbBlue
== 0xff) && (rgb
->rgbReserved
== 0));
155 static int bitmap_info_size( const BITMAPINFO
* info
, WORD coloruse
)
157 unsigned int colors
, size
, masks
= 0;
159 if (info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
161 const BITMAPCOREHEADER
*core
= (const BITMAPCOREHEADER
*)info
;
162 colors
= (core
->bcBitCount
<= 8) ? 1 << core
->bcBitCount
: 0;
163 return sizeof(BITMAPCOREHEADER
) + colors
*
164 ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBTRIPLE
) : sizeof(WORD
));
166 else /* assume BITMAPINFOHEADER */
168 colors
= info
->bmiHeader
.biClrUsed
;
169 if (colors
> 256) /* buffer overflow otherwise */
171 if (!colors
&& (info
->bmiHeader
.biBitCount
<= 8))
172 colors
= 1 << info
->bmiHeader
.biBitCount
;
173 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
) masks
= 3;
174 size
= max( info
->bmiHeader
.biSize
, sizeof(BITMAPINFOHEADER
) + masks
* sizeof(DWORD
) );
175 return size
+ colors
* ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBQUAD
) : sizeof(WORD
));
179 static int DIB_GetBitmapInfo( const BITMAPINFOHEADER
*header
, LONG
*width
,
180 LONG
*height
, WORD
*bpp
, DWORD
*compr
)
182 if (header
->biSize
== sizeof(BITMAPCOREHEADER
))
184 const BITMAPCOREHEADER
*core
= (const BITMAPCOREHEADER
*)header
;
185 *width
= core
->bcWidth
;
186 *height
= core
->bcHeight
;
187 *bpp
= core
->bcBitCount
;
191 else if (header
->biSize
== sizeof(BITMAPINFOHEADER
) ||
192 header
->biSize
== sizeof(BITMAPV4HEADER
) ||
193 header
->biSize
== sizeof(BITMAPV5HEADER
))
195 *width
= header
->biWidth
;
196 *height
= header
->biHeight
;
197 *bpp
= header
->biBitCount
;
198 *compr
= header
->biCompression
;
201 ERR("(%d): unknown/wrong size for header\n", header
->biSize
);
205 /* copy an icon bitmap, even when it can't be selected into a DC */
206 /* helper for CreateIconIndirect */
207 static void stretch_blt_icon(HDC hdc_dst
, int dst_width
, int dst_height
, HBITMAP src
)
209 HDC hdc
= CreateCompatibleDC( 0 );
213 GetObjectW(src
, sizeof(bm
), &bm
);
215 hbmpPrev
= SelectObject(hdc
, src
);
217 if (!hbmpPrev
) /* do it the hard way */
222 if (!(info
= HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )))) return;
223 info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
224 info
->bmiHeader
.biWidth
= bm
.bmWidth
;
225 info
->bmiHeader
.biHeight
= bm
.bmHeight
;
226 info
->bmiHeader
.biPlanes
= GetDeviceCaps( hdc_dst
, PLANES
);
227 info
->bmiHeader
.biBitCount
= GetDeviceCaps( hdc_dst
, BITSPIXEL
);
228 info
->bmiHeader
.biCompression
= BI_RGB
;
229 info
->bmiHeader
.biSizeImage
= get_dib_image_size( bm
.bmWidth
, bm
.bmHeight
, info
->bmiHeader
.biBitCount
);
230 info
->bmiHeader
.biXPelsPerMeter
= 0;
231 info
->bmiHeader
.biYPelsPerMeter
= 0;
232 info
->bmiHeader
.biClrUsed
= 0;
233 info
->bmiHeader
.biClrImportant
= 0;
234 bits
= HeapAlloc( GetProcessHeap(), 0, info
->bmiHeader
.biSizeImage
);
235 if (bits
&& GetDIBits( hdc
, src
, 0, bm
.bmHeight
, bits
, info
, DIB_RGB_COLORS
))
236 StretchDIBits( hdc_dst
, 0, 0, dst_width
, dst_height
,
237 0, 0, bm
.bmWidth
, bm
.bmHeight
, bits
, info
, DIB_RGB_COLORS
, SRCCOPY
);
239 HeapFree( GetProcessHeap(), 0, bits
);
240 HeapFree( GetProcessHeap(), 0, info
);
244 StretchBlt( hdc_dst
, 0, 0, dst_width
, dst_height
, hdc
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, SRCCOPY
);
245 SelectObject(hdc
, hbmpPrev
);
251 /***********************************************************************
254 static BOOL
bmi_has_alpha( const BITMAPINFO
*info
, const void *bits
)
257 BOOL has_alpha
= FALSE
;
258 const unsigned char *ptr
= bits
;
260 if (info
->bmiHeader
.biBitCount
!= 32) return FALSE
;
261 for (i
= 0; i
< info
->bmiHeader
.biWidth
* abs(info
->bmiHeader
.biHeight
); i
++, ptr
+= 4)
262 if ((has_alpha
= (ptr
[3] != 0))) break;
266 /***********************************************************************
267 * create_alpha_bitmap
269 * Create the alpha bitmap for a 32-bpp icon that has an alpha channel.
274 _In_opt_ HBITMAP color
,
275 _In_opt_ BITMAPINFO
*src_info
,
276 _In_opt_
const void *color_bits
,
280 HBITMAP alpha
= NULL
, hbmpOld
;
281 HDC hdc
= NULL
, hdcScreen
;
286 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
289 hdc
= CreateCompatibleDC(hdcScreen
);
299 BITMAPINFO
*info
= NULL
;
301 TRACE("Creating alpha bitmap from existing bitmap.\n");
303 if (!GetObjectW( color
, sizeof(bm
), &bm
))
305 if (bm
.bmBitsPixel
!= 32)
308 size
= get_dib_image_size(bm
.bmWidth
, bm
.bmHeight
, 32);
310 info
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(BITMAPINFO
, bmiColors
[256]));
313 info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
314 info
->bmiHeader
.biWidth
= bm
.bmWidth
;
315 info
->bmiHeader
.biHeight
= -bm
.bmHeight
;
316 info
->bmiHeader
.biPlanes
= 1;
317 info
->bmiHeader
.biBitCount
= 32;
318 info
->bmiHeader
.biCompression
= BI_RGB
;
319 info
->bmiHeader
.biSizeImage
= size
;
320 info
->bmiHeader
.biXPelsPerMeter
= 0;
321 info
->bmiHeader
.biYPelsPerMeter
= 0;
322 info
->bmiHeader
.biClrUsed
= 0;
323 info
->bmiHeader
.biClrImportant
= 0;
325 bits
= HeapAlloc(GetProcessHeap(), 0, size
);
328 HeapFree(GetProcessHeap(), 0, info
);
331 if(!GetDIBits( hdc
, color
, 0, bm
.bmHeight
, bits
, info
, DIB_RGB_COLORS
))
333 HeapFree(GetProcessHeap(), 0, info
);
336 if (!bmi_has_alpha( info
, bits
))
338 HeapFree(GetProcessHeap(), 0, info
);
342 /* pre-multiply by alpha */
343 for (ptr
= bits
; ptr
< ((BYTE
*)bits
+ size
); ptr
+= 4)
345 unsigned int alpha
= ptr
[3];
346 ptr
[0] = (ptr
[0] * alpha
) / 255;
347 ptr
[1] = (ptr
[1] * alpha
) / 255;
348 ptr
[2] = (ptr
[2] * alpha
) / 255;
351 /* Directly create a 32-bits DDB (thanks to undocumented CreateDIBitmap flag). */
352 alpha
= CreateDIBitmap(hdc
, NULL
, CBM_INIT
| 2, bits
, info
, DIB_RGB_COLORS
);
354 HeapFree(GetProcessHeap(), 0, info
);
360 LONG orig_width
, orig_height
;
362 TRACE("Creating alpha bitmap from bitmap info.\n");
364 if(!bmi_has_alpha(src_info
, color_bits
))
367 if(!DIB_GetBitmapInfo(&src_info
->bmiHeader
, &orig_width
, &orig_height
, &bpp
, &compr
))
372 size
= get_dib_image_size(orig_width
, orig_height
, bpp
);
373 bits
= HeapAlloc(GetProcessHeap(), 0, size
);
376 CopyMemory(bits
, color_bits
, size
);
377 /* pre-multiply by alpha */
378 for (ptr
= bits
; ptr
< ((BYTE
*)bits
+ size
); ptr
+= 4)
380 unsigned int alpha
= ptr
[3];
381 ptr
[0] = (ptr
[0] * alpha
) / 255;
382 ptr
[1] = (ptr
[1] * alpha
) / 255;
383 ptr
[2] = (ptr
[2] * alpha
) / 255;
386 /* Create the bitmap. Set the bitmap info to have the right width and height */
387 if(src_info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
389 ((BITMAPCOREHEADER
*)&src_info
->bmiHeader
)->bcWidth
= width
;
390 ((BITMAPCOREHEADER
*)&src_info
->bmiHeader
)->bcHeight
= height
;
394 src_info
->bmiHeader
.biWidth
= width
;
395 src_info
->bmiHeader
.biHeight
= height
;
397 /* Directly create a 32-bits DDB (thanks to undocumented CreateDIBitmap flag). */
398 alpha
= CreateDIBitmap(hdcScreen
, NULL
, 2, NULL
, src_info
, DIB_RGB_COLORS
);
400 if(src_info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
402 ((BITMAPCOREHEADER
*)&src_info
->bmiHeader
)->bcWidth
= orig_width
;
403 ((BITMAPCOREHEADER
*)&src_info
->bmiHeader
)->bcHeight
= orig_height
;
407 src_info
->bmiHeader
.biWidth
= orig_width
;
408 src_info
->bmiHeader
.biHeight
= orig_height
;
412 hbmpOld
= SelectObject(hdc
, alpha
);
419 if(!StretchDIBits( hdc
, 0, 0, width
, height
,
420 0, 0, orig_width
, orig_height
,
421 bits
, src_info
, DIB_RGB_COLORS
, SRCCOPY
))
423 SelectObject(hdc
, hbmpOld
);
430 SelectObject(hdc
, hbmpOld
);
437 if(bits
) HeapFree(GetProcessHeap(), 0, bits
);
439 TRACE("Returning 0x%08x.\n", alpha
);
443 #include "pshpack1.h"
454 } CURSORICONFILEDIRENTRY
;
461 CURSORICONFILEDIRENTRY idEntries
[1];
466 const CURSORICONFILEDIRENTRY
*
467 get_best_icon_file_entry(
468 _In_
const CURSORICONFILEDIR
* dir
,
469 _In_ DWORD dwFileSize
,
476 CURSORICONDIR
* fakeDir
;
477 CURSORICONDIRENTRY
* fakeEntry
;
479 const CURSORICONFILEDIRENTRY
* entry
;
481 /* Check our file is what it claims to be */
482 if ( dwFileSize
< sizeof(*dir
) )
485 if (dwFileSize
< FIELD_OFFSET(CURSORICONFILEDIR
, idEntries
[dir
->idCount
]))
490 * We allocate a buffer, fake it as if it was a pointer to a resource in a module,
491 * pass it to LookupIconIdFromDirectoryEx and get back the index we have to use
493 fakeDir
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(CURSORICONDIR
, idEntries
[dir
->idCount
]));
496 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
499 fakeDir
->idReserved
= 0;
500 fakeDir
->idType
= dir
->idType
;
501 fakeDir
->idCount
= dir
->idCount
;
502 for(i
= 0; i
<dir
->idCount
; i
++)
504 fakeEntry
= &fakeDir
->idEntries
[i
];
505 entry
= &dir
->idEntries
[i
];
506 /* Take this as an occasion to perform a size check */
507 if ((entry
->dwDIBOffset
> dwFileSize
)
508 || ((entry
->dwDIBOffset
+ entry
->dwDIBSize
) > dwFileSize
))
510 ERR("Corrupted icon file?.\n");
511 HeapFree(GetProcessHeap(), 0, fakeDir
);
514 /* File icon/cursors are not like resource ones */
517 fakeEntry
->ResInfo
.icon
.bWidth
= entry
->bWidth
;
518 fakeEntry
->ResInfo
.icon
.bHeight
= entry
->bHeight
;
519 fakeEntry
->ResInfo
.icon
.bColorCount
= 0;
520 fakeEntry
->ResInfo
.icon
.bReserved
= 0;
524 fakeEntry
->ResInfo
.cursor
.wWidth
= entry
->bWidth
;
525 fakeEntry
->ResInfo
.cursor
.wHeight
= entry
->bHeight
;
527 /* Let's assume there's always one plane */
528 fakeEntry
->wPlanes
= 1;
529 /* We must get the bitcount from the BITMAPINFOHEADER itself */
530 if (((BITMAPINFOHEADER
*)((char *)dir
+ entry
->dwDIBOffset
))->biSize
== sizeof(BITMAPCOREHEADER
))
531 fakeEntry
->wBitCount
= ((BITMAPCOREHEADER
*)((char *)dir
+ entry
->dwDIBOffset
))->bcBitCount
;
533 fakeEntry
->wBitCount
= ((BITMAPINFOHEADER
*)((char *)dir
+ entry
->dwDIBOffset
))->biBitCount
;
534 fakeEntry
->dwBytesInRes
= entry
->dwDIBSize
;
535 fakeEntry
->wResId
= i
+ 1;
538 /* Now call LookupIconIdFromResourceEx */
539 i
= LookupIconIdFromDirectoryEx((PBYTE
)fakeDir
, bIcon
, cxDesired
, cyDesired
, fuLoad
& LR_MONOCHROME
);
540 /* We don't need this anymore */
541 HeapFree(GetProcessHeap(), 0, fakeDir
);
544 WARN("Unable to get a fit entry index.\n");
549 return &dir
->idEntries
[i
-1];
553 get_best_icon_file_offset(
554 _In_
const LPBYTE dir
,
555 _In_ DWORD dwFileSize
,
560 _Out_ POINT
*ptHotSpot
563 const CURSORICONFILEDIRENTRY
*entry
;
565 entry
= get_best_icon_file_entry((CURSORICONFILEDIR
*) dir
, dwFileSize
, cxDesired
, cyDesired
, bIcon
, fuLoad
);
569 ptHotSpot
->x
= entry
->xHotspot
;
570 ptHotSpot
->y
= entry
->yHotspot
;
574 return entry
->dwDIBOffset
;
581 /************* IMPLEMENTATION CORE ****************/
583 static BOOL
CURSORICON_GetCursorDataFromBMI(
584 _Inout_ CURSORDATA
* pdata
,
585 _In_
const BITMAPINFO
*pbmi
588 UINT ubmiSize
= bitmap_info_size(pbmi
, DIB_RGB_COLORS
);
589 BOOL monochrome
= is_dib_monochrome(pbmi
);
595 BITMAPINFO
* pbmiCopy
;
596 HBITMAP hbmpOld
= NULL
;
597 BOOL bResult
= FALSE
;
598 const VOID
*pvColor
, *pvMask
;
600 ibmpType
= DIB_GetBitmapInfo(&pbmi
->bmiHeader
, &width
, &height
, &bpp
, &compr
);
605 /* No compression for icons */
609 /* If no dimensions were set, use the one from the icon */
610 if(!pdata
->cx
) pdata
->cx
= width
;
611 if(!pdata
->cy
) pdata
->cy
= height
< 0 ? -height
/2 : height
/2;
613 /* Fix the hotspot coords */
614 if(pdata
->rt
== (USHORT
)((ULONG_PTR
)RT_CURSOR
))
616 if(pdata
->cx
!= width
)
617 pdata
->xHotspot
= (pdata
->xHotspot
* pdata
->cx
) / width
;
618 if(pdata
->cy
!= height
/2)
619 pdata
->yHotspot
= (pdata
->yHotspot
* pdata
->cy
* 2) / height
;
623 pdata
->xHotspot
= pdata
->cx
/2;
624 pdata
->yHotspot
= pdata
->cy
/2;
627 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
630 hdc
= CreateCompatibleDC(hdcScreen
);
637 pbmiCopy
= HeapAlloc(GetProcessHeap(), 0, max(ubmiSize
, FIELD_OFFSET(BITMAPINFO
, bmiColors
[3])));
640 RtlCopyMemory(pbmiCopy
, pbmi
, ubmiSize
);
642 /* In an icon/cursor, the BITMAPINFO holds twice the height */
643 if(pbmiCopy
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
644 ((BITMAPCOREHEADER
*)&pbmiCopy
->bmiHeader
)->bcHeight
/= 2;
646 pbmiCopy
->bmiHeader
.biHeight
/= 2;
649 pvColor
= (const char*)pbmi
+ ubmiSize
;
650 pvMask
= (const char*)pvColor
+
651 get_dib_image_size(width
, height
, bpp
);
656 /* Create the 1bpp bitmap which will contain everything */
657 pdata
->hbmColor
= NULL
;
658 pdata
->hbmMask
= CreateBitmap(pdata
->cx
, pdata
->cy
* 2, 1, 1, NULL
);
661 hbmpOld
= SelectObject(hdc
, pdata
->hbmMask
);
665 if(!StretchDIBits(hdc
, 0, pdata
->cy
, pdata
->cx
, pdata
->cy
,
667 pvColor
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
))
673 /* Create the bitmap. It has to be compatible with the screen surface */
674 pdata
->hbmColor
= CreateCompatibleBitmap(hdcScreen
, pdata
->cx
, pdata
->cy
);
677 /* Create the 1bpp mask bitmap */
678 pdata
->hbmMask
= CreateBitmap(pdata
->cx
, pdata
->cy
, 1, 1, NULL
);
681 hbmpOld
= SelectObject(hdc
, pdata
->hbmColor
);
684 if(!StretchDIBits(hdc
, 0, 0, pdata
->cx
, pdata
->cy
,
686 pvColor
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
))
688 pdata
->bpp
= GetDeviceCaps(hdcScreen
, BITSPIXEL
);
689 pdata
->hbmAlpha
= create_alpha_bitmap(NULL
, pbmiCopy
, pvColor
, pdata
->cx
, pdata
->cy
);
691 /* Now convert the info to monochrome for the mask bits */
692 if (pbmiCopy
->bmiHeader
.biSize
!= sizeof(BITMAPCOREHEADER
))
694 RGBQUAD
*rgb
= pbmiCopy
->bmiColors
;
696 pbmiCopy
->bmiHeader
.biClrUsed
= pbmiCopy
->bmiHeader
.biClrImportant
= 2;
697 rgb
[0].rgbBlue
= rgb
[0].rgbGreen
= rgb
[0].rgbRed
= 0x00;
698 rgb
[1].rgbBlue
= rgb
[1].rgbGreen
= rgb
[1].rgbRed
= 0xff;
699 rgb
[0].rgbReserved
= rgb
[1].rgbReserved
= 0;
700 pbmiCopy
->bmiHeader
.biBitCount
= 1;
704 RGBTRIPLE
*rgb
= (RGBTRIPLE
*)(((BITMAPCOREHEADER
*)pbmiCopy
) + 1);
706 rgb
[0].rgbtBlue
= rgb
[0].rgbtGreen
= rgb
[0].rgbtRed
= 0x00;
707 rgb
[1].rgbtBlue
= rgb
[1].rgbtGreen
= rgb
[1].rgbtRed
= 0xff;
708 ((BITMAPCOREHEADER
*)&pbmiCopy
->bmiHeader
)->bcBitCount
= 1;
711 /* Set the mask bits */
712 if(!SelectObject(hdc
, pdata
->hbmMask
))
714 bResult
= StretchDIBits(hdc
, 0, 0, pdata
->cx
, pdata
->cy
,
716 pvMask
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
) != 0;
720 if(hbmpOld
) SelectObject(hdc
, hbmpOld
);
722 if(pbmiCopy
) HeapFree(GetProcessHeap(), 0, pbmiCopy
);
723 /* Clean up in case of failure */
726 if(pdata
->hbmMask
) DeleteObject(pdata
->hbmMask
);
727 if(pdata
->hbmColor
) DeleteObject(pdata
->hbmColor
);
728 if(pdata
->hbmAlpha
) DeleteObject(pdata
->hbmAlpha
);
733 static BOOL
CURSORICON_GetCursorDataFromIconInfo(
734 _Out_ CURSORDATA
* pCursorData
,
735 _In_ ICONINFO
* pIconInfo
740 ZeroMemory(pCursorData
, sizeof(*pCursorData
));
741 if(pIconInfo
->hbmColor
)
743 /* We must convert the color bitmap to screen format */
744 HDC hdcScreen
, hdcMem
;
747 /* The mask dictates its dimensions */
748 if (!GetObject(pIconInfo
->hbmMask
, sizeof(bm
), &bm
))
750 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
753 hdcMem
= CreateCompatibleDC(hdcScreen
);
759 pCursorData
->hbmColor
= CreateCompatibleBitmap(hdcScreen
, bm
.bmWidth
, bm
.bmHeight
);
761 if (!pCursorData
->hbmColor
)
766 hbmpPrev
= SelectObject(hdcMem
, pCursorData
->hbmColor
);
770 DeleteObject(pCursorData
->hbmColor
);
773 stretch_blt_icon( hdcMem
, bm
.bmWidth
, bm
.bmHeight
, pIconInfo
->hbmColor
);
774 SelectObject(hdcMem
, hbmpPrev
);
777 pCursorData
->hbmMask
= CopyImage(pIconInfo
->hbmMask
, IMAGE_BITMAP
, 0, 0, LR_MONOCHROME
);
778 if(!pCursorData
->hbmMask
)
781 /* Now, fill some information */
782 pCursorData
->rt
= (USHORT
)((ULONG_PTR
)(pIconInfo
->fIcon
? RT_ICON
: RT_CURSOR
));
783 if(pCursorData
->hbmColor
)
785 GetObject(pCursorData
->hbmColor
, sizeof(bm
), &bm
);
786 pCursorData
->bpp
= bm
.bmBitsPixel
;
787 pCursorData
->cx
= bm
.bmWidth
;
788 pCursorData
->cy
= bm
.bmHeight
;
789 if(pCursorData
->bpp
== 32)
790 pCursorData
->hbmAlpha
= create_alpha_bitmap(pCursorData
->hbmColor
, NULL
, NULL
, 0, 0);
794 GetObject(pCursorData
->hbmMask
, sizeof(bm
), &bm
);
795 pCursorData
->bpp
= 1;
796 pCursorData
->cx
= bm
.bmWidth
;
797 pCursorData
->cy
= bm
.bmHeight
/2;
802 pCursorData
->xHotspot
= pCursorData
->cx
/2;
803 pCursorData
->yHotspot
= pCursorData
->cy
/2;
807 pCursorData
->xHotspot
= pIconInfo
->xHotspot
;
808 pCursorData
->yHotspot
= pIconInfo
->yHotspot
;
815 #define RIFF_FOURCC( c0, c1, c2, c3 ) \
816 ( (DWORD)(BYTE)(c0) | ( (DWORD)(BYTE)(c1) << 8 ) | \
817 ( (DWORD)(BYTE)(c2) << 16 ) | ( (DWORD)(BYTE)(c3) << 24 ) )
819 #define ANI_RIFF_ID RIFF_FOURCC('R', 'I', 'F', 'F')
820 #define ANI_LIST_ID RIFF_FOURCC('L', 'I', 'S', 'T')
821 #define ANI_ACON_ID RIFF_FOURCC('A', 'C', 'O', 'N')
822 #define ANI_anih_ID RIFF_FOURCC('a', 'n', 'i', 'h')
823 #define ANI_seq__ID RIFF_FOURCC('s', 'e', 'q', ' ')
824 #define ANI_fram_ID RIFF_FOURCC('f', 'r', 'a', 'm')
825 #define ANI_rate_ID RIFF_FOURCC('r', 'a', 't', 'e')
827 #define ANI_FLAG_ICON 0x1
828 #define ANI_FLAG_SEQUENCE 0x2
830 #include <pshpack1.h>
845 const unsigned char *data
;
849 static void dump_ani_header( const ani_header
*header
)
851 TRACE(" header size: %d\n", header
->header_size
);
852 TRACE(" frames: %d\n", header
->num_frames
);
853 TRACE(" steps: %d\n", header
->num_steps
);
854 TRACE(" width: %d\n", header
->width
);
855 TRACE(" height: %d\n", header
->height
);
856 TRACE(" bpp: %d\n", header
->bpp
);
857 TRACE(" planes: %d\n", header
->num_planes
);
858 TRACE(" display rate: %d\n", header
->display_rate
);
859 TRACE(" flags: 0x%08x\n", header
->flags
);
862 /* Find an animated cursor chunk, given its type and ID */
863 static void riff_find_chunk( DWORD chunk_id
, DWORD chunk_type
, const riff_chunk_t
*parent_chunk
, riff_chunk_t
*chunk
)
865 const unsigned char *ptr
= parent_chunk
->data
;
866 const unsigned char *end
= parent_chunk
->data
+ (parent_chunk
->data_size
- (2 * sizeof(DWORD
)));
868 if (chunk_type
== ANI_LIST_ID
|| chunk_type
== ANI_RIFF_ID
) end
-= sizeof(DWORD
);
872 if ((!chunk_type
&& *(const DWORD
*)ptr
== chunk_id
)
873 || (chunk_type
&& *(const DWORD
*)ptr
== chunk_type
&& *((const DWORD
*)ptr
+ 2) == chunk_id
))
875 ptr
+= sizeof(DWORD
);
876 chunk
->data_size
= (*(const DWORD
*)ptr
+ 1) & ~1;
877 ptr
+= sizeof(DWORD
);
878 if (chunk_type
== ANI_LIST_ID
|| chunk_type
== ANI_RIFF_ID
) ptr
+= sizeof(DWORD
);
884 ptr
+= sizeof(DWORD
);
885 ptr
+= (*(const DWORD
*)ptr
+ 1) & ~1;
886 ptr
+= sizeof(DWORD
);
890 static BOOL
CURSORICON_GetCursorDataFromANI(
891 _Inout_ CURSORDATA
* pCurData
,
892 _In_
const BYTE
*pData
,
893 _In_ DWORD dwDataSize
,
898 const ani_header
*pHeader
;
899 riff_chunk_t root_chunk
= { dwDataSize
, pData
};
900 riff_chunk_t ACON_chunk
= {0};
901 riff_chunk_t anih_chunk
= {0};
902 riff_chunk_t fram_chunk
= {0};
903 riff_chunk_t rate_chunk
= {0};
904 riff_chunk_t seq_chunk
= {0};
905 const unsigned char *icon_chunk
;
906 const unsigned char *icon_data
;
908 /* Find the root chunk */
909 riff_find_chunk( ANI_ACON_ID
, ANI_RIFF_ID
, &root_chunk
, &ACON_chunk
);
910 if (!ACON_chunk
.data
)
912 ERR("Failed to get root chunk.\n");
916 /* Find the header chunk */
917 riff_find_chunk( ANI_anih_ID
, 0, &ACON_chunk
, &anih_chunk
);
918 if (!ACON_chunk
.data
)
920 ERR("Failed to get header chunk.\n");
923 pHeader
= (ani_header
*)anih_chunk
.data
;
924 dump_ani_header(pHeader
);
926 /* Set up the master data */
927 pCurData
->CURSORF_flags
|= CURSORF_ACON
;
928 pCurData
->cpcur
= pHeader
->num_frames
;
929 pCurData
->cicur
= pHeader
->num_steps
;
930 pCurData
->iicur
= pHeader
->display_rate
;
932 /* Get the sequences */
933 if (pHeader
->flags
& ANI_FLAG_SEQUENCE
)
935 riff_find_chunk( ANI_seq__ID
, 0, &ACON_chunk
, &seq_chunk
);
938 ERR("No sequence data although the flag is set!\n");
943 /* Get the frame rates */
944 riff_find_chunk( ANI_rate_ID
, 0, &ACON_chunk
, &rate_chunk
);
946 pCurData
->ajifRate
= (INT
*)rate_chunk
.data
;
948 /* Get the frames chunk */
949 riff_find_chunk( ANI_fram_ID
, ANI_LIST_ID
, &ACON_chunk
, &fram_chunk
);
950 if (!fram_chunk
.data
)
952 ERR("Failed to get icon list.\n");
955 icon_chunk
= fram_chunk
.data
;
956 icon_data
= fram_chunk
.data
+ (2 * sizeof(DWORD
));
958 if(pHeader
->num_frames
> 1)
960 /* Allocate frame descriptors, step indices and rates */
961 pCurData
->aspcur
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
962 pHeader
->num_frames
* sizeof(CURSORDATA
) + pHeader
->num_steps
* (sizeof(DWORD
) + sizeof(INT
)));
963 if(!pCurData
->aspcur
)
965 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
968 pCurData
->aicur
= (DWORD
*)(pCurData
->aspcur
+ pHeader
->num_frames
);
969 pCurData
->ajifRate
= (INT
*)(pCurData
->aicur
+ pHeader
->num_steps
);
972 for(i
=0; i
< pHeader
->num_frames
; i
++)
974 CURSORDATA
* pFrameData
;
975 const DWORD chunk_size
= *(const DWORD
*)(icon_chunk
+ sizeof(DWORD
));
976 const BITMAPINFO
* pbmi
;
978 if(pHeader
->num_frames
> 1)
979 pFrameData
= &pCurData
->aspcur
[i
];
981 pFrameData
= pCurData
;
983 pFrameData
->rt
= pCurData
->rt
;
985 if (pHeader
->flags
& ANI_FLAG_ICON
)
987 /* The chunks describe an icon file */
988 const CURSORICONFILEDIRENTRY
* pDirEntry
= get_best_icon_file_entry(
989 (const CURSORICONFILEDIR
*) icon_data
,
997 ERR("Unable to find the right file entry for frame %d.\n", i
);
1000 pFrameData
->xHotspot
= pDirEntry
->xHotspot
;
1001 pFrameData
->yHotspot
= pDirEntry
->yHotspot
;
1002 if(!pHeader
->width
|| !pHeader
->height
)
1004 pFrameData
->cx
= pDirEntry
->bWidth
;
1005 pFrameData
->cy
= pDirEntry
->bHeight
;
1009 pFrameData
->cx
= pHeader
->width
;
1010 pFrameData
->cy
= pHeader
->height
;
1012 pbmi
= (const BITMAPINFO
*) (icon_data
+ pDirEntry
->dwDIBOffset
);
1016 /* The chunks just describe bitmaps */
1017 pbmi
= (const BITMAPINFO
*)icon_data
;
1018 pFrameData
->xHotspot
= pFrameData
->yHotspot
= 0;
1021 /* Do the real work */
1022 CURSORICON_GetCursorDataFromBMI(pFrameData
, pbmi
);
1024 if(pHeader
->num_frames
> 1)
1025 pFrameData
->CURSORF_flags
|= CURSORF_ACONFRAME
;
1027 pFrameData
->CURSORF_flags
&= ~CURSORF_ACON
;
1031 icon_chunk
+= chunk_size
+ (2 * sizeof(DWORD
));
1032 icon_data
= icon_chunk
+ (2 * sizeof(DWORD
));
1035 if(pHeader
->num_frames
<= 1)
1039 CopyMemory(pCurData
->ajifRate
, rate_chunk
.data
, pHeader
->num_steps
* sizeof(INT
));
1042 for(i
=0; i
< pHeader
->num_steps
; i
++)
1043 pCurData
->ajifRate
[i
] = pHeader
->display_rate
;
1046 if (pHeader
->flags
& ANI_FLAG_SEQUENCE
)
1048 CopyMemory(pCurData
->aicur
, seq_chunk
.data
, pHeader
->num_steps
* sizeof(DWORD
));
1052 for(i
=0; i
< pHeader
->num_steps
; i
++)
1053 pCurData
->aicur
[i
] = i
;
1059 HeapFree(GetProcessHeap(), 0, pCurData
->aspcur
);
1060 ZeroMemory(pCurData
, sizeof(CURSORDATA
));
1068 _In_opt_ HINSTANCE hinst
,
1069 _In_ LPCWSTR lpszName
,
1075 const BITMAPINFO
* pbmi
;
1076 BITMAPINFO
* pbmiScaled
= NULL
;
1077 BITMAPINFO
* pbmiCopy
= NULL
;
1078 const VOID
* pvMapping
= NULL
;
1080 HGLOBAL hgRsrc
= NULL
;
1083 HDC hdcScreen
= NULL
;
1085 HBITMAP hbmpOld
, hbmpRet
= NULL
;
1090 /* Map the bitmap info */
1091 if(fuLoad
& LR_LOADFROMFILE
)
1093 const BITMAPFILEHEADER
* pbmfh
;
1095 pvMapping
= map_fileW(lpszName
, NULL
);
1099 if (pbmfh
->bfType
!= 0x4d42 /* 'BM' */)
1101 WARN("Invalid/unsupported bitmap format!\n");
1104 pbmi
= (const BITMAPINFO
*)(pbmfh
+ 1);
1106 /* Get the image bits */
1107 if(pbmfh
->bfOffBits
)
1108 dwOffset
= pbmfh
->bfOffBits
- sizeof(BITMAPFILEHEADER
);
1114 /* Caller wants an OEM bitmap */
1116 hinst
= User32Instance
;
1117 hrsrc
= FindResourceW(hinst
, lpszName
, RT_BITMAP
);
1120 hgRsrc
= LoadResource(hinst
, hrsrc
);
1123 pbmi
= LockResource(hgRsrc
);
1129 if(DIB_GetBitmapInfo(&pbmi
->bmiHeader
, &width
, &height
, &bpp
, &compr
) == -1)
1131 if((width
> 65535) || (height
> 65535))
1138 cyDesired
= -cyDesired
;
1140 iBMISize
= bitmap_info_size(pbmi
, DIB_RGB_COLORS
);
1142 /* Get a pointer to the image data */
1143 pvBits
= (char*)pbmi
+ (dwOffset
? dwOffset
: iBMISize
);
1145 /* Create a copy of the info describing the bitmap in the file */
1146 pbmiCopy
= HeapAlloc(GetProcessHeap(), 0, iBMISize
);
1149 CopyMemory(pbmiCopy
, pbmi
, iBMISize
);
1151 /* Fix it up, if needed */
1152 if(fuLoad
& (LR_LOADTRANSPARENT
| LR_LOADMAP3DCOLORS
))
1154 WORD bpp
, incr
, numColors
;
1157 COLORREF crWindow
, cr3DShadow
, cr3DFace
, cr3DLight
;
1158 BYTE pixel
= *((BYTE
*)pvBits
);
1161 if(pbmiCopy
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
1163 bpp
= ((BITMAPCOREHEADER
*)&pbmiCopy
->bmiHeader
)->bcBitCount
;
1164 numColors
= 1 << bpp
;
1165 /* BITMAPCOREINFO holds RGBTRIPLEs */
1170 bpp
= pbmiCopy
->bmiHeader
.biBitCount
;
1171 /* BITMAPINFOHEADER holds RGBQUADs */
1173 numColors
= pbmiCopy
->bmiHeader
.biClrUsed
;
1174 if(numColors
> 256) numColors
= 256;
1175 if (!numColors
&& (bpp
<= 8)) numColors
= 1 << bpp
;
1181 pbmiColors
= (char*)pbmiCopy
+ pbmiCopy
->bmiHeader
.biSize
;
1183 /* Get the relevant colors */
1184 crWindow
= GetSysColor(COLOR_WINDOW
);
1185 cr3DShadow
= GetSysColor(COLOR_3DSHADOW
);
1186 cr3DFace
= GetSysColor(COLOR_3DFACE
);
1187 cr3DLight
= GetSysColor(COLOR_3DLIGHT
);
1189 /* Fix the transparent palette entry */
1190 if(fuLoad
& LR_LOADTRANSPARENT
)
1194 case 1: pixel
>>= 7; break;
1195 case 4: pixel
>>= 4; break;
1198 FIXME("Unhandled bit depth %d.\n", bpp
);
1202 if(pixel
>= numColors
)
1204 ERR("Wrong pixel passed in.\n");
1208 /* If both flags are set, we must use COLOR_3DFACE */
1209 if(fuLoad
& LR_LOADMAP3DCOLORS
) crWindow
= cr3DFace
;
1211 /* Define the color */
1212 ptr
= (RGBTRIPLE
*)(pbmiColors
+ pixel
*incr
);
1213 ptr
->rgbtBlue
= GetBValue(crWindow
);
1214 ptr
->rgbtGreen
= GetGValue(crWindow
);
1215 ptr
->rgbtRed
= GetRValue(crWindow
);
1219 /* If we are here, then LR_LOADMAP3DCOLORS is set without LR_TRANSPARENT */
1220 for(i
= 0; i
<numColors
; i
++)
1222 ptr
= (RGBTRIPLE
*)(pbmiColors
+ i
*incr
);
1223 if((ptr
->rgbtBlue
== ptr
->rgbtRed
) && (ptr
->rgbtBlue
== ptr
->rgbtGreen
))
1225 if(ptr
->rgbtBlue
== 128)
1227 ptr
->rgbtBlue
= GetBValue(cr3DShadow
);
1228 ptr
->rgbtGreen
= GetGValue(cr3DShadow
);
1229 ptr
->rgbtRed
= GetRValue(cr3DShadow
);
1231 if(ptr
->rgbtBlue
== 192)
1233 ptr
->rgbtBlue
= GetBValue(cr3DFace
);
1234 ptr
->rgbtGreen
= GetGValue(cr3DFace
);
1235 ptr
->rgbtRed
= GetRValue(cr3DFace
);
1237 if(ptr
->rgbtBlue
== 223)
1239 ptr
->rgbtBlue
= GetBValue(cr3DLight
);
1240 ptr
->rgbtGreen
= GetGValue(cr3DLight
);
1241 ptr
->rgbtRed
= GetRValue(cr3DLight
);
1248 if(fuLoad
& LR_CREATEDIBSECTION
)
1250 /* Allocate the BMI describing the new bitmap */
1251 pbmiScaled
= HeapAlloc(GetProcessHeap(), 0, iBMISize
);
1254 CopyMemory(pbmiScaled
, pbmiCopy
, iBMISize
);
1257 if(pbmiScaled
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
1259 BITMAPCOREHEADER
* pbmch
= (BITMAPCOREHEADER
*)&pbmiScaled
->bmiHeader
;
1260 pbmch
->bcWidth
= cxDesired
;
1261 pbmch
->bcHeight
= cyDesired
;
1265 pbmiScaled
->bmiHeader
.biWidth
= cxDesired
;
1266 pbmiScaled
->bmiHeader
.biHeight
= cyDesired
;
1267 /* No compression for DIB sections */
1268 pbmiScaled
->bmiHeader
.biCompression
= BI_RGB
;
1272 /* Top-down image */
1273 if(cyDesired
< 0) cyDesired
= -cyDesired
;
1275 /* We need a device context */
1276 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
1279 hdc
= CreateCompatibleDC(hdcScreen
);
1283 /* Now create the bitmap */
1284 if(fuLoad
& LR_CREATEDIBSECTION
)
1285 hbmpRet
= CreateDIBSection(hdc
, pbmiScaled
, DIB_RGB_COLORS
, NULL
, 0, 0);
1288 if(is_dib_monochrome(pbmiCopy
) || (fuLoad
& LR_MONOCHROME
))
1289 hbmpRet
= CreateBitmap(cxDesired
, cyDesired
, 1, 1, NULL
);
1291 hbmpRet
= CreateCompatibleBitmap(hdcScreen
, cxDesired
, cyDesired
);
1297 hbmpOld
= SelectObject(hdc
, hbmpRet
);
1300 if(!StretchDIBits(hdc
, 0, 0, cxDesired
, cyDesired
,
1301 0, 0, pbmi
->bmiHeader
.biWidth
, pbmi
->bmiHeader
.biHeight
,
1302 pvBits
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
))
1304 ERR("StretchDIBits failed!.\n");
1305 SelectObject(hdc
, hbmpOld
);
1306 DeleteObject(hbmpRet
);
1311 SelectObject(hdc
, hbmpOld
);
1315 DeleteDC(hdcScreen
);
1319 HeapFree(GetProcessHeap(), 0, pbmiScaled
);
1321 HeapFree(GetProcessHeap(), 0, pbmiCopy
);
1323 UnmapViewOfFile( pvMapping
);
1325 FreeResource(hgRsrc
);
1333 CURSORICON_LoadFromFileW(
1334 _In_ LPCWSTR lpszName
,
1341 const CURSORICONFILEDIRENTRY
*entry
;
1342 const CURSORICONFILEDIR
*dir
;
1345 HANDLE hCurIcon
= NULL
;
1346 CURSORDATA cursorData
;
1348 TRACE("loading %s\n", debugstr_w( lpszName
));
1350 bits
= map_fileW( lpszName
, &filesize
);
1354 /* Check for .ani. */
1355 if (memcmp( bits
, "RIFF", 4 ) == 0)
1361 dir
= (CURSORICONFILEDIR
*) bits
;
1362 entry
= get_best_icon_file_entry(dir
, filesize
, cxDesired
, cyDesired
, bIcon
, fuLoad
);
1366 /* Fix dimensions */
1367 if(!cxDesired
) cxDesired
= entry
->bWidth
;
1368 if(!cyDesired
) cyDesired
= entry
->bHeight
;
1369 /* A bit of preparation */
1370 ZeroMemory(&cursorData
, sizeof(cursorData
));
1373 cursorData
.xHotspot
= entry
->xHotspot
;
1374 cursorData
.yHotspot
= entry
->yHotspot
;
1376 cursorData
.rt
= (USHORT
)((ULONG_PTR
)(bIcon
? RT_ICON
: RT_CURSOR
));
1379 if(!CURSORICON_GetCursorDataFromBMI(&cursorData
, (BITMAPINFO
*)(&bits
[entry
->dwDIBOffset
])))
1382 hCurIcon
= NtUserxCreateEmptyCurObject(FALSE
);
1387 if(!NtUserSetCursorIconData(hCurIcon
, NULL
, NULL
, &cursorData
))
1389 NtUserDestroyCursor(hCurIcon
, TRUE
);
1394 UnmapViewOfFile(bits
);
1399 DeleteObject(cursorData
.hbmMask
);
1400 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
1401 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
1402 UnmapViewOfFile(bits
);
1409 CURSORICON_LoadImageW(
1410 _In_opt_ HINSTANCE hinst
,
1411 _In_ LPCWSTR lpszName
,
1419 HANDLE handle
, hCurIcon
= NULL
;
1423 CURSORDATA cursorData
;
1425 UNICODE_STRING ustrRsrc
;
1426 UNICODE_STRING ustrModule
= {0, 0, NULL
};
1428 /* Fix width/height */
1429 if(fuLoad
& LR_DEFAULTSIZE
)
1431 if(!cxDesired
) cxDesired
= GetSystemMetrics(bIcon
? SM_CXICON
: SM_CXCURSOR
);
1432 if(!cyDesired
) cyDesired
= GetSystemMetrics(bIcon
? SM_CYICON
: SM_CYCURSOR
);
1435 if(fuLoad
& LR_LOADFROMFILE
)
1437 return CURSORICON_LoadFromFileW(lpszName
, cxDesired
, cyDesired
, fuLoad
, bIcon
);
1440 /* Check if caller wants OEM icons */
1442 hinst
= User32Instance
;
1446 /* Prepare the resource name string */
1447 if(IS_INTRESOURCE(lpszName
))
1449 ustrRsrc
.Buffer
= (LPWSTR
)lpszName
;
1450 ustrRsrc
.Length
= 0;
1451 ustrRsrc
.MaximumLength
= 0;
1454 RtlInitUnicodeString(&ustrRsrc
, lpszName
);
1459 DWORD size
= MAX_PATH
;
1460 /* Get the module name string */
1464 ustrModule
.Buffer
= HeapAlloc(GetProcessHeap(), 0, size
*sizeof(WCHAR
));
1465 if (!ustrModule
.Buffer
)
1467 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1470 ret
= GetModuleFileNameW(hinst
, ustrModule
.Buffer
, size
);
1473 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1477 /* This API is completely broken... */
1480 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1485 ustrModule
.Buffer
[ret
] = UNICODE_NULL
;
1486 ustrModule
.Length
= ret
* sizeof(WCHAR
);
1487 ustrModule
.MaximumLength
= size
* sizeof(WCHAR
);
1492 if(fuLoad
& LR_SHARED
)
1494 FINDEXISTINGCURICONPARAM param
;
1496 TRACE("Checking for an LR_SHARED cursor/icon.\n");
1498 param
.bIcon
= bIcon
;
1499 param
.cx
= cxDesired
;
1500 param
.cy
= cyDesired
;
1501 hCurIcon
= NtUserFindExistingCursorIcon(&ustrModule
, &ustrRsrc
, ¶m
);
1504 /* Woohoo, got it! */
1505 TRACE("MATCH! %p\n",hCurIcon
);
1506 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1511 /* Find resource ID */
1512 hrsrc
= FindResourceW(
1515 bIcon
? RT_GROUP_ICON
: RT_GROUP_CURSOR
);
1517 /* We let FindResource, LoadResource, etc. call SetLastError */
1521 handle
= LoadResource(hinst
, hrsrc
);
1525 dir
= LockResource(handle
);
1529 wResId
= LookupIconIdFromDirectoryEx((PBYTE
)dir
, bIcon
, cxDesired
, cyDesired
, fuLoad
);
1530 FreeResource(handle
);
1532 /* Get the relevant resource pointer */
1533 hrsrc
= FindResourceW(
1535 MAKEINTRESOURCEW(wResId
),
1536 bIcon
? RT_ICON
: RT_CURSOR
);
1540 handle
= LoadResource(hinst
, hrsrc
);
1544 bits
= LockResource(handle
);
1547 FreeResource(handle
);
1551 ZeroMemory(&cursorData
, sizeof(cursorData
));
1553 /* This is from resource */
1554 cursorData
.CURSORF_flags
= CURSORF_FROMRESOURCE
;
1556 if(dir
->idType
== 2)
1558 /* idType == 2 for cursor resources */
1559 SHORT
* ptr
= (SHORT
*)bits
;
1560 cursorData
.xHotspot
= ptr
[0];
1561 cursorData
.yHotspot
= ptr
[1];
1562 bits
+= 2*sizeof(SHORT
);
1564 cursorData
.cx
= cxDesired
;
1565 cursorData
.cy
= cyDesired
;
1566 cursorData
.rt
= (USHORT
)((ULONG_PTR
)(bIcon
? RT_ICON
: RT_CURSOR
));
1568 /* Get the bitmaps */
1569 bStatus
= CURSORICON_GetCursorDataFromBMI(
1573 FreeResource( handle
);
1578 /* Create the handle */
1579 hCurIcon
= NtUserxCreateEmptyCurObject(FALSE
);
1585 if(fuLoad
& LR_SHARED
)
1587 cursorData
.CURSORF_flags
|= CURSORF_LRSHARED
;
1591 bStatus
= NtUserSetCursorIconData(hCurIcon
, hinst
? &ustrModule
: NULL
, lpszName
? &ustrRsrc
: NULL
, &cursorData
);
1595 NtUserDestroyCursor(hCurIcon
, TRUE
);
1600 if(ustrModule
.Buffer
)
1601 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1605 if(ustrModule
.Buffer
)
1606 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1607 DeleteObject(cursorData
.hbmMask
);
1608 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
1609 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
1628 objSize
= GetObjectW( hnd
, sizeof(ds
), &ds
);
1629 if (!objSize
) return 0;
1630 if ((desiredx
< 0) || (desiredy
< 0)) return 0;
1632 if (flags
& LR_COPYFROMRESOURCE
)
1634 FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
1637 if (flags
& LR_COPYRETURNORG
)
1639 FIXME("The flag LR_COPYRETURNORG is not implemented for bitmaps\n");
1642 if (desiredx
== 0) desiredx
= ds
.dsBm
.bmWidth
;
1643 if (desiredy
== 0) desiredy
= ds
.dsBm
.bmHeight
;
1645 /* Allocate memory for a BITMAPINFOHEADER structure and a
1646 color table. The maximum number of colors in a color table
1647 is 256 which corresponds to a bitmap with depth 8.
1648 Bitmaps with higher depths don't have color tables. */
1649 bi
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
));
1652 bi
->bmiHeader
.biSize
= sizeof(bi
->bmiHeader
);
1653 bi
->bmiHeader
.biPlanes
= ds
.dsBm
.bmPlanes
;
1654 bi
->bmiHeader
.biBitCount
= ds
.dsBm
.bmBitsPixel
;
1655 bi
->bmiHeader
.biCompression
= BI_RGB
;
1657 if (flags
& LR_CREATEDIBSECTION
)
1659 /* Create a DIB section. LR_MONOCHROME is ignored */
1661 HDC dc
= CreateCompatibleDC(NULL
);
1663 if (objSize
== sizeof(DIBSECTION
))
1665 /* The source bitmap is a DIB.
1666 Get its attributes to create an exact copy */
1667 memcpy(bi
, &ds
.dsBmih
, sizeof(BITMAPINFOHEADER
));
1670 bi
->bmiHeader
.biWidth
= desiredx
;
1671 bi
->bmiHeader
.biHeight
= desiredy
;
1673 /* Get the color table or the color masks */
1674 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
1676 res
= CreateDIBSection(dc
, bi
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
1681 /* Create a device-dependent bitmap */
1683 BOOL monochrome
= (flags
& LR_MONOCHROME
);
1685 if (objSize
== sizeof(DIBSECTION
))
1687 /* The source bitmap is a DIB section.
1688 Get its attributes */
1689 HDC dc
= CreateCompatibleDC(NULL
);
1690 bi
->bmiHeader
.biWidth
= ds
.dsBm
.bmWidth
;
1691 bi
->bmiHeader
.biHeight
= ds
.dsBm
.bmHeight
;
1692 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
1695 if (!monochrome
&& ds
.dsBm
.bmBitsPixel
== 1)
1697 /* Look if the colors of the DIB are black and white */
1700 (bi
->bmiColors
[0].rgbRed
== 0xff
1701 && bi
->bmiColors
[0].rgbGreen
== 0xff
1702 && bi
->bmiColors
[0].rgbBlue
== 0xff
1703 && bi
->bmiColors
[0].rgbReserved
== 0
1704 && bi
->bmiColors
[1].rgbRed
== 0
1705 && bi
->bmiColors
[1].rgbGreen
== 0
1706 && bi
->bmiColors
[1].rgbBlue
== 0
1707 && bi
->bmiColors
[1].rgbReserved
== 0)
1709 (bi
->bmiColors
[0].rgbRed
== 0
1710 && bi
->bmiColors
[0].rgbGreen
== 0
1711 && bi
->bmiColors
[0].rgbBlue
== 0
1712 && bi
->bmiColors
[0].rgbReserved
== 0
1713 && bi
->bmiColors
[1].rgbRed
== 0xff
1714 && bi
->bmiColors
[1].rgbGreen
== 0xff
1715 && bi
->bmiColors
[1].rgbBlue
== 0xff
1716 && bi
->bmiColors
[1].rgbReserved
== 0);
1719 else if (!monochrome
)
1721 monochrome
= ds
.dsBm
.bmBitsPixel
== 1;
1726 res
= CreateBitmap(desiredx
, desiredy
, 1, 1, NULL
);
1730 HDC screenDC
= GetDC(NULL
);
1731 res
= CreateCompatibleBitmap(screenDC
, desiredx
, desiredy
);
1732 ReleaseDC(NULL
, screenDC
);
1738 /* Only copy the bitmap if it's a DIB section or if it's
1739 compatible to the screen */
1742 if (objSize
== sizeof(DIBSECTION
))
1744 copyContents
= TRUE
;
1748 HDC screenDC
= GetDC(NULL
);
1749 int screen_depth
= GetDeviceCaps(screenDC
, BITSPIXEL
);
1750 ReleaseDC(NULL
, screenDC
);
1752 copyContents
= (ds
.dsBm
.bmBitsPixel
== 1 || ds
.dsBm
.bmBitsPixel
== screen_depth
);
1757 /* The source bitmap may already be selected in a device context,
1758 use GetDIBits/StretchDIBits and not StretchBlt */
1763 dc
= CreateCompatibleDC(NULL
);
1765 bi
->bmiHeader
.biWidth
= ds
.dsBm
.bmWidth
;
1766 bi
->bmiHeader
.biHeight
= ds
.dsBm
.bmHeight
;
1767 bi
->bmiHeader
.biSizeImage
= 0;
1768 bi
->bmiHeader
.biClrUsed
= 0;
1769 bi
->bmiHeader
.biClrImportant
= 0;
1771 /* Fill in biSizeImage */
1772 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
1773 bits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, bi
->bmiHeader
.biSizeImage
);
1779 /* Get the image bits of the source bitmap */
1780 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, bits
, bi
, DIB_RGB_COLORS
);
1782 /* Copy it to the destination bitmap */
1783 oldBmp
= SelectObject(dc
, res
);
1784 StretchDIBits(dc
, 0, 0, desiredx
, desiredy
,
1785 0, 0, ds
.dsBm
.bmWidth
, ds
.dsBm
.bmHeight
,
1786 bits
, bi
, DIB_RGB_COLORS
, SRCCOPY
);
1787 SelectObject(dc
, oldBmp
);
1789 HeapFree(GetProcessHeap(), 0, bits
);
1795 if (flags
& LR_COPYDELETEORG
)
1800 HeapFree(GetProcessHeap(), 0, bi
);
1806 CURSORICON_CopyImage(
1816 CURSORDATA CursorData
;
1818 if (fuFlags
& LR_COPYFROMRESOURCE
)
1820 /* Get the icon module/resource names */
1821 UNICODE_STRING ustrModule
;
1822 UNICODE_STRING ustrRsrc
;
1825 ustrModule
.MaximumLength
= 0;
1826 ustrRsrc
.MaximumLength
= 0;
1828 /* Get the buffer size */
1829 if (!NtUserGetIconInfo(hicon
, NULL
, &ustrModule
, &ustrRsrc
, NULL
, FALSE
))
1834 ustrModule
.Buffer
= HeapAlloc(GetProcessHeap(), 0, ustrModule
.MaximumLength
);
1835 if (!ustrModule
.Buffer
)
1837 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1841 if (ustrRsrc
.MaximumLength
)
1843 ustrRsrc
.Buffer
= HeapAlloc(GetProcessHeap(), 0, ustrRsrc
.MaximumLength
);
1844 if (!ustrRsrc
.Buffer
)
1846 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1847 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1852 if (!NtUserGetIconInfo(hicon
, NULL
, &ustrModule
, &ustrRsrc
, NULL
, FALSE
))
1854 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1855 if (!IS_INTRESOURCE(ustrRsrc
.Buffer
))
1856 HeapFree(GetProcessHeap(), 0, ustrRsrc
.Buffer
);
1860 /* NULL-terminate our strings */
1861 ustrModule
.Buffer
[ustrModule
.Length
/sizeof(WCHAR
)] = UNICODE_NULL
;
1862 if (!IS_INTRESOURCE(ustrRsrc
.Buffer
))
1863 ustrRsrc
.Buffer
[ustrRsrc
.Length
/sizeof(WCHAR
)] = UNICODE_NULL
;
1865 TRACE("Got module %wZ, resource %p (%S).\n", &ustrModule
,
1866 ustrRsrc
.Buffer
, IS_INTRESOURCE(ustrRsrc
.Buffer
) ? L
"" : ustrRsrc
.Buffer
);
1868 /* Get the module handle */
1869 if (!GetModuleHandleExW(0, ustrModule
.Buffer
, &hModule
))
1871 /* This should never happen */
1872 ERR("Invalid handle? Module='%wZ', error %lu.\n", &ustrModule
, GetLastError());
1873 SetLastError(ERROR_INVALID_PARAMETER
);
1877 /* Call the relevant function */
1878 ret
= CURSORICON_LoadImageW(
1883 fuFlags
& (LR_DEFAULTSIZE
| LR_SHARED
),
1886 FreeLibrary(hModule
);
1888 /* If we're here, that means that the passed icon is shared. Don't destroy it, even if LR_COPYDELETEORG is specified */
1890 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1891 if (!IS_INTRESOURCE(ustrRsrc
.Buffer
))
1892 HeapFree(GetProcessHeap(), 0, ustrRsrc
.Buffer
);
1894 TRACE("Returning 0x%08x.\n", ret
);
1899 /* This is a regular copy */
1900 if (fuFlags
& ~(LR_COPYDELETEORG
| LR_SHARED
))
1901 FIXME("Unimplemented flags: 0x%08x\n", fuFlags
);
1903 if (!GetIconInfo(hicon
, &ii
))
1905 ERR("GetIconInfo failed.\n");
1909 /* This is CreateIconIndirect with the LR_SHARED coat added */
1910 if (!CURSORICON_GetCursorDataFromIconInfo(&CursorData
, &ii
))
1913 if (fuFlags
& LR_SHARED
)
1914 CursorData
.CURSORF_flags
|= CURSORF_LRSHARED
;
1916 ret
= NtUserxCreateEmptyCurObject(FALSE
);
1920 if (!NtUserSetCursorIconData(ret
, NULL
, NULL
, &CursorData
))
1922 NtUserDestroyCursor(ret
, TRUE
);
1927 DeleteObject(ii
.hbmMask
);
1928 if (ii
.hbmColor
) DeleteObject(ii
.hbmColor
);
1930 if (ret
&& (fuFlags
& LR_COPYDELETEORG
))
1937 User32CallCopyImageFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
1939 PCOPYIMAGE_CALLBACK_ARGUMENTS Common
;
1941 Common
= (PCOPYIMAGE_CALLBACK_ARGUMENTS
) Arguments
;
1943 Result
= CopyImage(Common
->hImage
,
1949 return ZwCallbackReturn(&Result
, sizeof(HANDLE
), STATUS_SUCCESS
);
1953 /************* PUBLIC FUNCTIONS *******************/
1955 HANDLE WINAPI
CopyImage(
1963 TRACE("hImage=%p, uType=%u, cxDesired=%d, cyDesired=%d, fuFlags=%x\n",
1964 hImage
, uType
, cxDesired
, cyDesired
, fuFlags
);
1968 return BITMAP_CopyImage(hImage
, cxDesired
, cyDesired
, fuFlags
);
1971 return CURSORICON_CopyImage(hImage
, uType
== IMAGE_ICON
, cxDesired
, cyDesired
, fuFlags
);
1973 SetLastError(ERROR_INVALID_PARAMETER
);
1979 HICON WINAPI
CopyIcon(
1983 return CURSORICON_CopyImage(hIcon
, FALSE
, 0, 0, 0);
1986 BOOL WINAPI
DrawIcon(
1993 return DrawIconEx(hDC
, X
, Y
, hIcon
, 0, 0, 0, NULL
, DI_NORMAL
| DI_COMPAT
| DI_DEFAULTSIZE
);
1996 BOOL WINAPI
DrawIconEx(
2003 _In_ UINT istepIfAniCur
,
2004 _In_opt_ HBRUSH hbrFlickerFreeDraw
,
2008 return NtUserDrawIconEx(hdc
, xLeft
, yTop
, hIcon
, cxWidth
, cyWidth
,
2009 istepIfAniCur
, hbrFlickerFreeDraw
, diFlags
,
2013 BOOL WINAPI
GetIconInfo(
2015 _Out_ PICONINFO piconinfo
2018 return NtUserGetIconInfo(hIcon
, piconinfo
, NULL
, NULL
, NULL
, FALSE
);
2021 BOOL WINAPI
DestroyIcon(
2025 return NtUserDestroyCursor(hIcon
, FALSE
);
2028 HICON WINAPI
LoadIconA(
2029 _In_opt_ HINSTANCE hInstance
,
2030 _In_ LPCSTR lpIconName
2033 TRACE("%p, %s\n", hInstance
, debugstr_a(lpIconName
));
2035 return LoadImageA(hInstance
,
2040 LR_SHARED
| LR_DEFAULTSIZE
);
2043 HICON WINAPI
LoadIconW(
2044 _In_opt_ HINSTANCE hInstance
,
2045 _In_ LPCWSTR lpIconName
2048 TRACE("%p, %s\n", hInstance
, debugstr_w(lpIconName
));
2050 return LoadImageW(hInstance
,
2055 LR_SHARED
| LR_DEFAULTSIZE
);
2058 HCURSOR WINAPI
LoadCursorA(
2059 _In_opt_ HINSTANCE hInstance
,
2060 _In_ LPCSTR lpCursorName
2063 TRACE("%p, %s\n", hInstance
, debugstr_a(lpCursorName
));
2065 return LoadImageA(hInstance
,
2070 LR_SHARED
| LR_DEFAULTSIZE
);
2073 HCURSOR WINAPI
LoadCursorW(
2074 _In_opt_ HINSTANCE hInstance
,
2075 _In_ LPCWSTR lpCursorName
2078 TRACE("%p, %s\n", hInstance
, debugstr_w(lpCursorName
));
2080 return LoadImageW(hInstance
,
2085 LR_SHARED
| LR_DEFAULTSIZE
);
2088 HCURSOR WINAPI
LoadCursorFromFileA(
2089 _In_ LPCSTR lpFileName
2092 TRACE("%s\n", debugstr_a(lpFileName
));
2094 return LoadImageA(NULL
,
2099 LR_LOADFROMFILE
| LR_DEFAULTSIZE
);
2102 HCURSOR WINAPI
LoadCursorFromFileW(
2103 _In_ LPCWSTR lpFileName
2106 TRACE("%s\n", debugstr_w(lpFileName
));
2108 return LoadImageW(NULL
,
2113 LR_LOADFROMFILE
| LR_DEFAULTSIZE
);
2116 HBITMAP WINAPI
LoadBitmapA(
2117 _In_opt_ HINSTANCE hInstance
,
2118 _In_ LPCSTR lpBitmapName
2121 TRACE("%p, %s\n", hInstance
, debugstr_a(lpBitmapName
));
2123 return LoadImageA(hInstance
,
2131 HBITMAP WINAPI
LoadBitmapW(
2132 _In_opt_ HINSTANCE hInstance
,
2133 _In_ LPCWSTR lpBitmapName
2136 TRACE("%p, %s\n", hInstance
, debugstr_w(lpBitmapName
));
2138 return LoadImageW(hInstance
,
2146 HANDLE WINAPI
LoadImageA(
2147 _In_opt_ HINSTANCE hinst
,
2148 _In_ LPCSTR lpszName
,
2159 if (IS_INTRESOURCE(lpszName
))
2160 return LoadImageW(hinst
, (LPCWSTR
)lpszName
, uType
, cxDesired
, cyDesired
, fuLoad
);
2162 len
= MultiByteToWideChar( CP_ACP
, 0, lpszName
, -1, NULL
, 0 );
2163 u_name
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
2164 MultiByteToWideChar( CP_ACP
, 0, lpszName
, -1, u_name
, len
);
2166 res
= LoadImageW(hinst
, u_name
, uType
, cxDesired
, cyDesired
, fuLoad
);
2167 HeapFree(GetProcessHeap(), 0, u_name
);
2171 HANDLE WINAPI
LoadImageW(
2172 _In_opt_ HINSTANCE hinst
,
2173 _In_ LPCWSTR lpszName
,
2180 TRACE("hinst 0x%p, name %s, uType 0x%08x, cxDesired %d, cyDesired %d, fuLoad 0x%08x.\n",
2181 hinst
, debugstr_w(lpszName
), uType
, cxDesired
, cyDesired
, fuLoad
);
2182 /* Redirect to each implementation */
2186 return BITMAP_LoadImageW(hinst
, lpszName
, cxDesired
, cyDesired
, fuLoad
);
2189 return CURSORICON_LoadImageW(hinst
, lpszName
, cxDesired
, cyDesired
, fuLoad
, uType
== IMAGE_ICON
);
2191 SetLastError(ERROR_INVALID_PARAMETER
);
2197 int WINAPI
LookupIconIdFromDirectory(
2198 _In_ PBYTE presbits
,
2202 return LookupIconIdFromDirectoryEx( presbits
, fIcon
,
2203 fIcon
? GetSystemMetrics(SM_CXICON
) : GetSystemMetrics(SM_CXCURSOR
),
2204 fIcon
? GetSystemMetrics(SM_CYICON
) : GetSystemMetrics(SM_CYCURSOR
), fIcon
? 0 : LR_MONOCHROME
);
2207 int WINAPI
LookupIconIdFromDirectoryEx(
2208 _In_ PBYTE presbits
,
2216 CURSORICONDIR
* dir
= (CURSORICONDIR
*)presbits
;
2217 CURSORICONDIRENTRY
* entry
;
2218 int i
, numMatch
= 0, iIndex
= -1;
2219 WORD width
, height
, BitCount
= 0;
2220 BOOL notPaletted
= FALSE
;
2221 ULONG bestScore
= 0xFFFFFFFF, score
;
2223 TRACE("%p, %x, %i, %i, %x.\n", presbits
, fIcon
, cxDesired
, cyDesired
, Flags
);
2225 if(!(dir
&& !dir
->idReserved
&& (dir
->idType
& 3)))
2227 WARN("Invalid resource.\n");
2231 if(Flags
& LR_MONOCHROME
)
2236 icScreen
= CreateICW(DISPLAYW
, NULL
, NULL
, NULL
);
2240 bppDesired
= GetDeviceCaps(icScreen
, BITSPIXEL
);
2245 cxDesired
= Flags
& LR_DEFAULTSIZE
? GetSystemMetrics(fIcon
? SM_CXICON
: SM_CXCURSOR
) : 256;
2247 cyDesired
= Flags
& LR_DEFAULTSIZE
? GetSystemMetrics(fIcon
? SM_CYICON
: SM_CYCURSOR
) : 256;
2249 /* Find the best match for the desired size */
2250 for(i
= 0; i
< dir
->idCount
; i
++)
2252 entry
= &dir
->idEntries
[i
];
2253 width
= fIcon
? entry
->ResInfo
.icon
.bWidth
: entry
->ResInfo
.cursor
.wWidth
;
2254 /* Height is twice as big in cursor resources */
2255 height
= fIcon
? entry
->ResInfo
.icon
.bHeight
: entry
->ResInfo
.cursor
.wHeight
/2;
2256 /* 0 represents 256 */
2257 if(!width
) width
= 256;
2258 if(!height
) height
= 256;
2259 /* Calculate the "score" (lower is better) */
2260 score
= 2*(abs(width
- cxDesired
) + abs(height
- cyDesired
));
2261 if( score
> bestScore
)
2263 /* Bigger than requested lowers the score */
2264 if(width
> cxDesired
)
2265 score
-= width
- cxDesired
;
2266 if(height
> cyDesired
)
2267 score
-= height
- cyDesired
;
2268 if(score
> bestScore
)
2270 if(score
== bestScore
)
2272 if(entry
->wBitCount
> BitCount
)
2273 BitCount
= entry
->wBitCount
;
2280 BitCount
= entry
->wBitCount
;
2285 /* Only one entry fits the asked dimensions */
2286 return dir
->idEntries
[iIndex
].wResId
;
2289 /* Avoid paletted icons on non-paletted device */
2290 if (bppDesired
> 8 && BitCount
> 8)
2295 /* Now find the entry with the best depth */
2296 for(i
= 0; i
< dir
->idCount
; i
++)
2298 entry
= &dir
->idEntries
[i
];
2299 width
= fIcon
? entry
->ResInfo
.icon
.bWidth
: entry
->ResInfo
.cursor
.wWidth
;
2300 height
= fIcon
? entry
->ResInfo
.icon
.bHeight
: entry
->ResInfo
.cursor
.wHeight
/2;
2301 /* 0 represents 256 */
2302 if(!width
) width
= 256;
2303 if(!height
) height
= 256;
2304 /* Check if this is the best match we had */
2305 score
= 2*(abs(width
- cxDesired
) + abs(height
- cyDesired
));
2306 if(width
> cxDesired
)
2307 score
-= width
- cxDesired
;
2308 if(height
> cyDesired
)
2309 score
-= height
- cyDesired
;
2310 if(score
!= bestScore
)
2313 if(entry
->wBitCount
== bppDesired
)
2314 return entry
->wResId
;
2315 /* We take the highest possible but smaller than the display depth */
2316 if((entry
->wBitCount
> BitCount
) && (entry
->wBitCount
< bppDesired
))
2318 /* Avoid paletted icons on non paletted devices */
2319 if ((entry
->wBitCount
<= 8) && notPaletted
)
2322 BitCount
= entry
->wBitCount
;
2327 return dir
->idEntries
[iIndex
].wResId
;
2329 /* No inferior or equal depth available. Get the smallest bigger one */
2332 for(i
= 0; i
< dir
->idCount
; i
++)
2334 entry
= &dir
->idEntries
[i
];
2335 width
= fIcon
? entry
->ResInfo
.icon
.bWidth
: entry
->ResInfo
.cursor
.wWidth
;
2336 height
= fIcon
? entry
->ResInfo
.icon
.bHeight
: entry
->ResInfo
.cursor
.wHeight
/2;
2337 /* 0 represents 256 */
2338 if(!width
) width
= 256;
2339 if(!height
) height
= 256;
2340 /* Check if this is the best match we had */
2341 score
= 2*(abs(width
- cxDesired
) + abs(height
- cyDesired
));
2342 if(width
> cxDesired
)
2343 score
-= width
- cxDesired
;
2344 if(height
> cyDesired
)
2345 score
-= height
- cyDesired
;
2346 if(score
!= bestScore
)
2348 /* Check the bit depth */
2349 if(entry
->wBitCount
< BitCount
)
2351 if((entry
->wBitCount
<= 8) && notPaletted
)
2354 BitCount
= entry
->wBitCount
;
2358 return dir
->idEntries
[iIndex
].wResId
;
2363 HICON WINAPI
CreateIcon(
2364 _In_opt_ HINSTANCE hInstance
,
2368 _In_ BYTE cBitsPixel
,
2369 _In_
const BYTE
*lpbANDbits
,
2370 _In_
const BYTE
*lpbXORbits
2376 TRACE_(icon
)("%dx%d, planes %d, bpp %d, xor %p, and %p\n",
2377 nWidth
, nHeight
, cPlanes
, cBitsPixel
, lpbXORbits
, lpbANDbits
);
2380 iinfo
.xHotspot
= nWidth
/ 2;
2381 iinfo
.yHotspot
= nHeight
/ 2;
2382 if (cPlanes
* cBitsPixel
> 1)
2384 iinfo
.hbmColor
= CreateBitmap( nWidth
, nHeight
, cPlanes
, cBitsPixel
, lpbXORbits
);
2385 iinfo
.hbmMask
= CreateBitmap( nWidth
, nHeight
, 1, 1, lpbANDbits
);
2389 iinfo
.hbmMask
= CreateBitmap( nWidth
, nHeight
* 2, 1, 1, lpbANDbits
);
2390 iinfo
.hbmColor
= NULL
;
2393 hIcon
= CreateIconIndirect( &iinfo
);
2395 DeleteObject( iinfo
.hbmMask
);
2396 if (iinfo
.hbmColor
) DeleteObject( iinfo
.hbmColor
);
2401 HICON WINAPI
CreateIconFromResource(
2402 _In_ PBYTE presbits
,
2403 _In_ DWORD dwResSize
,
2408 return CreateIconFromResourceEx( presbits
, dwResSize
, fIcon
, dwVer
, 0, 0, LR_DEFAULTSIZE
| LR_SHARED
);
2411 HICON WINAPI
CreateIconFromResourceEx(
2412 _In_ PBYTE pbIconBits
,
2413 _In_ DWORD cbIconBits
,
2415 _In_ DWORD dwVersion
,
2421 CURSORDATA cursorData
;
2425 TRACE("%p, %lu, %lu, %lu, %i, %i, %lu.\n", pbIconBits
, cbIconBits
, fIcon
, dwVersion
, cxDesired
, cyDesired
, uFlags
);
2427 if(uFlags
& LR_DEFAULTSIZE
)
2429 if(!cxDesired
) cxDesired
= GetSystemMetrics(fIcon
? SM_CXICON
: SM_CXCURSOR
);
2430 if(!cyDesired
) cyDesired
= GetSystemMetrics(fIcon
? SM_CYICON
: SM_CYCURSOR
);
2433 ZeroMemory(&cursorData
, sizeof(cursorData
));
2434 cursorData
.cx
= cxDesired
;
2435 cursorData
.cy
= cyDesired
;
2436 cursorData
.rt
= (USHORT
)((ULONG_PTR
)(fIcon
? RT_ICON
: RT_CURSOR
));
2438 /* Convert to win32k-ready data */
2439 if(!memcmp(pbIconBits
, "RIFF", 4))
2441 if(!CURSORICON_GetCursorDataFromANI(&cursorData
, pbIconBits
, cbIconBits
, uFlags
))
2443 ERR("Could not get cursor data from .ani.\n");
2446 isAnimated
= !!(cursorData
.CURSORF_flags
& CURSORF_ACON
);
2450 /* It is possible to pass Icon Directories to this API */
2451 int wResId
= LookupIconIdFromDirectoryEx(pbIconBits
, fIcon
, cxDesired
, cyDesired
, uFlags
);
2452 HANDLE ResHandle
= NULL
;
2457 CURSORICONDIR
* pCurIconDir
= (CURSORICONDIR
*)pbIconBits
;
2459 TRACE("Pointer points to a directory structure.\n");
2461 /* So this is a pointer to an icon directory structure. Find the module */
2462 if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
| GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
,
2463 (LPCWSTR
)pbIconBits
,
2469 /* Check we were given the right type of resource */
2470 if((fIcon
&& pCurIconDir
->idType
== 2) || (!fIcon
&& pCurIconDir
->idType
== 1))
2472 WARN("Got a %s directory pointer, but called for a %s", fIcon
? "cursor" : "icon", fIcon
? "icon" : "cursor");
2476 /* Get the relevant resource pointer */
2477 hrsrc
= FindResourceW(
2479 MAKEINTRESOURCEW(wResId
),
2480 fIcon
? RT_ICON
: RT_CURSOR
);
2484 ResHandle
= LoadResource(hinst
, hrsrc
);
2488 pbIconBits
= LockResource(ResHandle
);
2491 FreeResource(ResHandle
);
2497 WORD
* pt
= (WORD
*)pbIconBits
;
2498 cursorData
.xHotspot
= *pt
++;
2499 cursorData
.yHotspot
= *pt
++;
2500 pbIconBits
= (PBYTE
)pt
;
2503 if (!CURSORICON_GetCursorDataFromBMI(&cursorData
, (BITMAPINFO
*)pbIconBits
))
2505 ERR("Couldn't fill the CURSORDATA structure.\n");
2507 FreeResource(ResHandle
);
2511 FreeResource(ResHandle
);
2515 if (uFlags
& LR_SHARED
)
2516 cursorData
.CURSORF_flags
|= CURSORF_LRSHARED
;
2518 hIcon
= NtUserxCreateEmptyCurObject(isAnimated
);
2522 if(!NtUserSetCursorIconData(hIcon
, NULL
, NULL
, &cursorData
))
2524 ERR("NtUserSetCursorIconData failed.\n");
2525 NtUserDestroyCursor(hIcon
, TRUE
);
2530 HeapFree(GetProcessHeap(), 0, cursorData
.aspcur
);
2537 HeapFree(GetProcessHeap(), 0, cursorData
.aspcur
);
2538 DeleteObject(cursorData
.hbmMask
);
2539 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
2540 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
2545 HICON WINAPI
CreateIconIndirect(
2546 _In_ PICONINFO piconinfo
2549 /* As simple as creating a handle, and let win32k deal with the bitmaps */
2551 CURSORDATA cursorData
;
2553 TRACE("%p.\n", piconinfo
);
2555 ZeroMemory(&cursorData
, sizeof(cursorData
));
2557 if(!CURSORICON_GetCursorDataFromIconInfo(&cursorData
, piconinfo
))
2560 hiconRet
= NtUserxCreateEmptyCurObject(FALSE
);
2564 if(!NtUserSetCursorIconData(hiconRet
, NULL
, NULL
, &cursorData
))
2566 NtUserDestroyCursor(hiconRet
, FALSE
);
2570 TRACE("Returning 0x%08x.\n", hiconRet
);
2576 DeleteObject(cursorData
.hbmMask
);
2577 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
2578 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
2583 HCURSOR WINAPI
CreateCursor(
2584 _In_opt_ HINSTANCE hInst
,
2589 _In_
const VOID
*pvANDPlane
,
2590 _In_
const VOID
*pvXORPlane
2596 TRACE_(cursor
)("%dx%d spot=%d,%d xor=%p and=%p\n",
2597 nWidth
, nHeight
, xHotSpot
, yHotSpot
, pvXORPlane
, pvANDPlane
);
2600 info
.xHotspot
= xHotSpot
;
2601 info
.yHotspot
= yHotSpot
;
2602 info
.hbmMask
= CreateBitmap( nWidth
, nHeight
, 1, 1, pvANDPlane
);
2603 info
.hbmColor
= CreateBitmap( nWidth
, nHeight
, 1, 1, pvXORPlane
);
2604 hCursor
= CreateIconIndirect( &info
);
2605 DeleteObject( info
.hbmMask
);
2606 DeleteObject( info
.hbmColor
);
2610 BOOL WINAPI
SetSystemCursor(
2617 hcur
= LoadImageW( 0, MAKEINTRESOURCE(id
), IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
);
2623 return NtUserSetSystemCursor(hcur
,id
);
2626 BOOL WINAPI
SetCursorPos(
2631 return NtUserxSetCursorPos(X
,Y
);
2634 BOOL WINAPI
GetCursorPos(
2635 _Out_ LPPOINT lpPoint
2638 return NtUserxGetCursorPos(lpPoint
);
2641 int WINAPI
ShowCursor(
2645 return NtUserxShowCursor(bShow
);
2648 HCURSOR WINAPI
GetCursor(void)
2650 return (HCURSOR
)NtUserGetThreadState(THREADSTATE_GETCURSOR
);
2653 BOOL WINAPI
DestroyCursor(
2654 _In_ HCURSOR hCursor
2657 return NtUserDestroyCursor(hCursor
, FALSE
);
2662 GetCursorFrameInfo(HCURSOR hCursor
, DWORD reserved
, DWORD istep
, PINT rate_jiffies
, DWORD
*num_steps
)
2664 return NtUserGetCursorFrameInfo(hCursor
, istep
, rate_jiffies
, num_steps
);