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
.biSize
== sizeof(BITMAPCOREHEADER
))
122 const RGBTRIPLE
*rgb
= ((const BITMAPCOREINFO
*)info
)->bmciColors
;
124 if (((const BITMAPCOREINFO
*)info
)->bmciHeader
.bcBitCount
!= 1) return FALSE
;
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 if (info
->bmiHeader
.biBitCount
!= 1) return FALSE
;
143 /* Check if the first color is black */
144 if ((rgb
->rgbRed
== 0) && (rgb
->rgbGreen
== 0) &&
145 (rgb
->rgbBlue
== 0) && (rgb
->rgbReserved
== 0))
149 /* Check if the second color is white */
150 return ((rgb
->rgbRed
== 0xff) && (rgb
->rgbGreen
== 0xff)
151 && (rgb
->rgbBlue
== 0xff) && (rgb
->rgbReserved
== 0));
157 static int bitmap_info_size( const BITMAPINFO
* info
, WORD coloruse
)
159 unsigned int colors
, size
, masks
= 0;
161 if (info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
163 const BITMAPCOREHEADER
*core
= (const BITMAPCOREHEADER
*)info
;
164 colors
= (core
->bcBitCount
<= 8) ? 1 << core
->bcBitCount
: 0;
165 return sizeof(BITMAPCOREHEADER
) + colors
*
166 ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBTRIPLE
) : sizeof(WORD
));
168 else /* assume BITMAPINFOHEADER */
170 colors
= info
->bmiHeader
.biClrUsed
;
171 if (colors
> 256) /* buffer overflow otherwise */
173 if (!colors
&& (info
->bmiHeader
.biBitCount
<= 8))
174 colors
= 1 << info
->bmiHeader
.biBitCount
;
175 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
) masks
= 3;
176 size
= max( info
->bmiHeader
.biSize
, sizeof(BITMAPINFOHEADER
) + masks
* sizeof(DWORD
) );
177 return size
+ colors
* ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBQUAD
) : sizeof(WORD
));
181 static int DIB_GetBitmapInfo( const BITMAPINFOHEADER
*header
, LONG
*width
,
182 LONG
*height
, WORD
*bpp
, DWORD
*compr
)
184 if (header
->biSize
== sizeof(BITMAPCOREHEADER
))
186 const BITMAPCOREHEADER
*core
= (const BITMAPCOREHEADER
*)header
;
187 *width
= core
->bcWidth
;
188 *height
= core
->bcHeight
;
189 *bpp
= core
->bcBitCount
;
193 else if (header
->biSize
== sizeof(BITMAPINFOHEADER
) ||
194 header
->biSize
== sizeof(BITMAPV4HEADER
) ||
195 header
->biSize
== sizeof(BITMAPV5HEADER
))
197 *width
= header
->biWidth
;
198 *height
= header
->biHeight
;
199 *bpp
= header
->biBitCount
;
200 *compr
= header
->biCompression
;
203 ERR("(%d): unknown/wrong size for header\n", header
->biSize
);
207 /* copy an icon bitmap, even when it can't be selected into a DC */
208 /* helper for CreateIconIndirect */
209 static void stretch_blt_icon(HDC hdc_dst
, int dst_width
, int dst_height
, HBITMAP src
)
211 HDC hdc
= CreateCompatibleDC( 0 );
215 GetObjectW(src
, sizeof(bm
), &bm
);
217 hbmpPrev
= SelectObject(hdc
, src
);
219 if (!hbmpPrev
) /* do it the hard way */
224 if (!(info
= HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )))) return;
225 info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
226 info
->bmiHeader
.biWidth
= bm
.bmWidth
;
227 info
->bmiHeader
.biHeight
= bm
.bmHeight
;
228 info
->bmiHeader
.biPlanes
= GetDeviceCaps( hdc_dst
, PLANES
);
229 info
->bmiHeader
.biBitCount
= GetDeviceCaps( hdc_dst
, BITSPIXEL
);
230 info
->bmiHeader
.biCompression
= BI_RGB
;
231 info
->bmiHeader
.biSizeImage
= get_dib_image_size( bm
.bmWidth
, bm
.bmHeight
, info
->bmiHeader
.biBitCount
);
232 info
->bmiHeader
.biXPelsPerMeter
= 0;
233 info
->bmiHeader
.biYPelsPerMeter
= 0;
234 info
->bmiHeader
.biClrUsed
= 0;
235 info
->bmiHeader
.biClrImportant
= 0;
236 bits
= HeapAlloc( GetProcessHeap(), 0, info
->bmiHeader
.biSizeImage
);
237 if (bits
&& GetDIBits( hdc
, src
, 0, bm
.bmHeight
, bits
, info
, DIB_RGB_COLORS
))
238 StretchDIBits( hdc_dst
, 0, 0, dst_width
, dst_height
,
239 0, 0, bm
.bmWidth
, bm
.bmHeight
, bits
, info
, DIB_RGB_COLORS
, SRCCOPY
);
241 HeapFree( GetProcessHeap(), 0, bits
);
242 HeapFree( GetProcessHeap(), 0, info
);
246 StretchBlt( hdc_dst
, 0, 0, dst_width
, dst_height
, hdc
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, SRCCOPY
);
247 SelectObject(hdc
, hbmpPrev
);
253 /***********************************************************************
256 static BOOL
bmi_has_alpha( const BITMAPINFO
*info
, const void *bits
)
259 BOOL has_alpha
= FALSE
;
260 const unsigned char *ptr
= bits
;
262 if (info
->bmiHeader
.biBitCount
!= 32) return FALSE
;
263 for (i
= 0; i
< info
->bmiHeader
.biWidth
* abs(info
->bmiHeader
.biHeight
); i
++, ptr
+= 4)
264 if ((has_alpha
= (ptr
[3] != 0))) break;
268 /***********************************************************************
269 * create_alpha_bitmap
271 * Create the alpha bitmap for a 32-bpp icon that has an alpha channel.
276 _In_opt_ HBITMAP color
,
277 _In_opt_ BITMAPINFO
*src_info
,
278 _In_opt_
const void *color_bits
,
282 HBITMAP alpha
= NULL
, hbmpOld
;
283 HDC hdc
= NULL
, hdcScreen
;
288 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
291 hdc
= CreateCompatibleDC(hdcScreen
);
301 BITMAPINFO
*info
= NULL
;
303 TRACE("Creating alpha bitmap from existing bitmap.\n");
305 if (!GetObjectW( color
, sizeof(bm
), &bm
))
307 if (bm
.bmBitsPixel
!= 32)
310 size
= get_dib_image_size(bm
.bmWidth
, bm
.bmHeight
, 32);
312 info
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(BITMAPINFO
, bmiColors
[256]));
315 info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
316 info
->bmiHeader
.biWidth
= bm
.bmWidth
;
317 info
->bmiHeader
.biHeight
= -bm
.bmHeight
;
318 info
->bmiHeader
.biPlanes
= 1;
319 info
->bmiHeader
.biBitCount
= 32;
320 info
->bmiHeader
.biCompression
= BI_RGB
;
321 info
->bmiHeader
.biSizeImage
= size
;
322 info
->bmiHeader
.biXPelsPerMeter
= 0;
323 info
->bmiHeader
.biYPelsPerMeter
= 0;
324 info
->bmiHeader
.biClrUsed
= 0;
325 info
->bmiHeader
.biClrImportant
= 0;
327 bits
= HeapAlloc(GetProcessHeap(), 0, size
);
330 HeapFree(GetProcessHeap(), 0, info
);
333 if(!GetDIBits( hdc
, color
, 0, bm
.bmHeight
, bits
, info
, DIB_RGB_COLORS
))
335 HeapFree(GetProcessHeap(), 0, info
);
338 if (!bmi_has_alpha( info
, bits
))
340 HeapFree(GetProcessHeap(), 0, info
);
344 /* pre-multiply by alpha */
345 for (ptr
= bits
; ptr
< ((BYTE
*)bits
+ size
); ptr
+= 4)
347 unsigned int alpha
= ptr
[3];
348 ptr
[0] = (ptr
[0] * alpha
) / 255;
349 ptr
[1] = (ptr
[1] * alpha
) / 255;
350 ptr
[2] = (ptr
[2] * alpha
) / 255;
353 /* Directly create a 32-bits DDB (thanks to undocumented CreateDIBitmap flag). */
354 alpha
= CreateDIBitmap(hdc
, NULL
, CBM_INIT
| 2, bits
, info
, DIB_RGB_COLORS
);
356 HeapFree(GetProcessHeap(), 0, info
);
362 LONG orig_width
, orig_height
;
364 TRACE("Creating alpha bitmap from bitmap info.\n");
366 if(!bmi_has_alpha(src_info
, color_bits
))
369 if(!DIB_GetBitmapInfo(&src_info
->bmiHeader
, &orig_width
, &orig_height
, &bpp
, &compr
))
374 size
= get_dib_image_size(orig_width
, orig_height
, bpp
);
375 bits
= HeapAlloc(GetProcessHeap(), 0, size
);
378 CopyMemory(bits
, color_bits
, size
);
379 /* pre-multiply by alpha */
380 for (ptr
= bits
; ptr
< ((BYTE
*)bits
+ size
); ptr
+= 4)
382 unsigned int alpha
= ptr
[3];
383 ptr
[0] = (ptr
[0] * alpha
) / 255;
384 ptr
[1] = (ptr
[1] * alpha
) / 255;
385 ptr
[2] = (ptr
[2] * alpha
) / 255;
388 /* Create the bitmap. Set the bitmap info to have the right width and height */
389 if(src_info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
391 ((BITMAPCOREHEADER
*)&src_info
->bmiHeader
)->bcWidth
= width
;
392 ((BITMAPCOREHEADER
*)&src_info
->bmiHeader
)->bcHeight
= height
;
396 src_info
->bmiHeader
.biWidth
= width
;
397 src_info
->bmiHeader
.biHeight
= height
;
399 /* Directly create a 32-bits DDB (thanks to undocumented CreateDIBitmap flag). */
400 alpha
= CreateDIBitmap(hdcScreen
, NULL
, 2, NULL
, src_info
, DIB_RGB_COLORS
);
402 if(src_info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
404 ((BITMAPCOREHEADER
*)&src_info
->bmiHeader
)->bcWidth
= orig_width
;
405 ((BITMAPCOREHEADER
*)&src_info
->bmiHeader
)->bcHeight
= orig_height
;
409 src_info
->bmiHeader
.biWidth
= orig_width
;
410 src_info
->bmiHeader
.biHeight
= orig_height
;
414 hbmpOld
= SelectObject(hdc
, alpha
);
421 if(!StretchDIBits( hdc
, 0, 0, width
, height
,
422 0, 0, orig_width
, orig_height
,
423 bits
, src_info
, DIB_RGB_COLORS
, SRCCOPY
))
425 SelectObject(hdc
, hbmpOld
);
432 SelectObject(hdc
, hbmpOld
);
439 if(bits
) HeapFree(GetProcessHeap(), 0, bits
);
441 TRACE("Returning 0x%08x.\n", alpha
);
445 #include "pshpack1.h"
456 } CURSORICONFILEDIRENTRY
;
463 CURSORICONFILEDIRENTRY idEntries
[1];
468 const CURSORICONFILEDIRENTRY
*
469 get_best_icon_file_entry(
470 _In_
const CURSORICONFILEDIR
* dir
,
471 _In_ DWORD dwFileSize
,
478 CURSORICONDIR
* fakeDir
;
479 CURSORICONDIRENTRY
* fakeEntry
;
481 const CURSORICONFILEDIRENTRY
* entry
;
483 /* Check our file is what it claims to be */
484 if ( dwFileSize
< sizeof(*dir
) )
487 if (dwFileSize
< FIELD_OFFSET(CURSORICONFILEDIR
, idEntries
[dir
->idCount
]))
492 * We allocate a buffer, fake it as if it was a pointer to a resource in a module,
493 * pass it to LookupIconIdFromDirectoryEx and get back the index we have to use
495 fakeDir
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(CURSORICONDIR
, idEntries
[dir
->idCount
]));
498 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
501 fakeDir
->idReserved
= 0;
502 fakeDir
->idType
= dir
->idType
;
503 fakeDir
->idCount
= dir
->idCount
;
504 for(i
= 0; i
<dir
->idCount
; i
++)
506 fakeEntry
= &fakeDir
->idEntries
[i
];
507 entry
= &dir
->idEntries
[i
];
508 /* Take this as an occasion to perform a size check */
509 if ((entry
->dwDIBOffset
> dwFileSize
)
510 || ((entry
->dwDIBOffset
+ entry
->dwDIBSize
) > dwFileSize
))
512 ERR("Corrupted icon file?.\n");
513 HeapFree(GetProcessHeap(), 0, fakeDir
);
516 /* File icon/cursors are not like resource ones */
519 fakeEntry
->ResInfo
.icon
.bWidth
= entry
->bWidth
;
520 fakeEntry
->ResInfo
.icon
.bHeight
= entry
->bHeight
;
521 fakeEntry
->ResInfo
.icon
.bColorCount
= 0;
522 fakeEntry
->ResInfo
.icon
.bReserved
= 0;
526 fakeEntry
->ResInfo
.cursor
.wWidth
= entry
->bWidth
;
527 fakeEntry
->ResInfo
.cursor
.wHeight
= entry
->bHeight
;
529 /* Let's assume there's always one plane */
530 fakeEntry
->wPlanes
= 1;
531 /* We must get the bitcount from the BITMAPINFOHEADER itself */
532 if (((BITMAPINFOHEADER
*)((char *)dir
+ entry
->dwDIBOffset
))->biSize
== sizeof(BITMAPCOREHEADER
))
533 fakeEntry
->wBitCount
= ((BITMAPCOREHEADER
*)((char *)dir
+ entry
->dwDIBOffset
))->bcBitCount
;
535 fakeEntry
->wBitCount
= ((BITMAPINFOHEADER
*)((char *)dir
+ entry
->dwDIBOffset
))->biBitCount
;
536 fakeEntry
->dwBytesInRes
= entry
->dwDIBSize
;
537 fakeEntry
->wResId
= i
+ 1;
540 /* Now call LookupIconIdFromResourceEx */
541 i
= LookupIconIdFromDirectoryEx((PBYTE
)fakeDir
, bIcon
, cxDesired
, cyDesired
, fuLoad
& LR_MONOCHROME
);
542 /* We don't need this anymore */
543 HeapFree(GetProcessHeap(), 0, fakeDir
);
546 WARN("Unable to get a fit entry index.\n");
551 return &dir
->idEntries
[i
-1];
555 get_best_icon_file_offset(
556 _In_
const LPBYTE dir
,
557 _In_ DWORD dwFileSize
,
562 _Out_ POINT
*ptHotSpot
565 const CURSORICONFILEDIRENTRY
*entry
;
567 entry
= get_best_icon_file_entry((CURSORICONFILEDIR
*) dir
, dwFileSize
, cxDesired
, cyDesired
, bIcon
, fuLoad
);
571 ptHotSpot
->x
= entry
->xHotspot
;
572 ptHotSpot
->y
= entry
->yHotspot
;
576 return entry
->dwDIBOffset
;
583 /************* IMPLEMENTATION CORE ****************/
585 static BOOL
CURSORICON_GetCursorDataFromBMI(
586 _Inout_ CURSORDATA
* pdata
,
587 _In_
const BITMAPINFO
*pbmi
590 UINT ubmiSize
= bitmap_info_size(pbmi
, DIB_RGB_COLORS
);
591 BOOL monochrome
= is_dib_monochrome(pbmi
);
597 BITMAPINFO
* pbmiCopy
;
598 HBITMAP hbmpOld
= NULL
;
599 BOOL bResult
= FALSE
;
600 const VOID
*pvColor
, *pvMask
;
602 ibmpType
= DIB_GetBitmapInfo(&pbmi
->bmiHeader
, &width
, &height
, &bpp
, &compr
);
607 /* No compression for icons */
611 /* If no dimensions were set, use the one from the icon */
612 if(!pdata
->cx
) pdata
->cx
= width
;
613 if(!pdata
->cy
) pdata
->cy
= height
< 0 ? -height
/2 : height
/2;
615 /* Fix the hotspot coords */
616 if(pdata
->rt
== (USHORT
)((ULONG_PTR
)RT_CURSOR
))
618 if(pdata
->cx
!= width
)
619 pdata
->xHotspot
= (pdata
->xHotspot
* pdata
->cx
) / width
;
620 if(pdata
->cy
!= height
/2)
621 pdata
->yHotspot
= (pdata
->yHotspot
* pdata
->cy
* 2) / height
;
625 pdata
->xHotspot
= pdata
->cx
/2;
626 pdata
->yHotspot
= pdata
->cy
/2;
629 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
632 hdc
= CreateCompatibleDC(hdcScreen
);
639 pbmiCopy
= HeapAlloc(GetProcessHeap(), 0, max(ubmiSize
, FIELD_OFFSET(BITMAPINFO
, bmiColors
[3])));
642 RtlCopyMemory(pbmiCopy
, pbmi
, ubmiSize
);
644 /* In an icon/cursor, the BITMAPINFO holds twice the height */
645 if(pbmiCopy
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
646 ((BITMAPCOREHEADER
*)&pbmiCopy
->bmiHeader
)->bcHeight
/= 2;
648 pbmiCopy
->bmiHeader
.biHeight
/= 2;
651 pvColor
= (const char*)pbmi
+ ubmiSize
;
652 pvMask
= (const char*)pvColor
+
653 get_dib_image_size(width
, height
, bpp
);
658 /* Create the 1bpp bitmap which will contain everything */
659 pdata
->hbmColor
= NULL
;
660 pdata
->hbmMask
= CreateBitmap(pdata
->cx
, pdata
->cy
* 2, 1, 1, NULL
);
663 hbmpOld
= SelectObject(hdc
, pdata
->hbmMask
);
667 if(!StretchDIBits(hdc
, 0, pdata
->cy
, pdata
->cx
, pdata
->cy
,
669 pvColor
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
))
675 /* Create the bitmap. It has to be compatible with the screen surface */
676 pdata
->hbmColor
= CreateCompatibleBitmap(hdcScreen
, pdata
->cx
, pdata
->cy
);
679 /* Create the 1bpp mask bitmap */
680 pdata
->hbmMask
= CreateBitmap(pdata
->cx
, pdata
->cy
, 1, 1, NULL
);
683 hbmpOld
= SelectObject(hdc
, pdata
->hbmColor
);
686 if(!StretchDIBits(hdc
, 0, 0, pdata
->cx
, pdata
->cy
,
688 pvColor
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
))
690 pdata
->bpp
= GetDeviceCaps(hdcScreen
, BITSPIXEL
);
691 pdata
->hbmAlpha
= create_alpha_bitmap(NULL
, pbmiCopy
, pvColor
, pdata
->cx
, pdata
->cy
);
693 /* Now convert the info to monochrome for the mask bits */
694 if (pbmiCopy
->bmiHeader
.biSize
!= sizeof(BITMAPCOREHEADER
))
696 RGBQUAD
*rgb
= pbmiCopy
->bmiColors
;
698 pbmiCopy
->bmiHeader
.biClrUsed
= pbmiCopy
->bmiHeader
.biClrImportant
= 2;
699 rgb
[0].rgbBlue
= rgb
[0].rgbGreen
= rgb
[0].rgbRed
= 0x00;
700 rgb
[1].rgbBlue
= rgb
[1].rgbGreen
= rgb
[1].rgbRed
= 0xff;
701 rgb
[0].rgbReserved
= rgb
[1].rgbReserved
= 0;
702 pbmiCopy
->bmiHeader
.biBitCount
= 1;
706 RGBTRIPLE
*rgb
= (RGBTRIPLE
*)(((BITMAPCOREHEADER
*)pbmiCopy
) + 1);
708 rgb
[0].rgbtBlue
= rgb
[0].rgbtGreen
= rgb
[0].rgbtRed
= 0x00;
709 rgb
[1].rgbtBlue
= rgb
[1].rgbtGreen
= rgb
[1].rgbtRed
= 0xff;
710 ((BITMAPCOREHEADER
*)&pbmiCopy
->bmiHeader
)->bcBitCount
= 1;
713 /* Set the mask bits */
714 if(!SelectObject(hdc
, pdata
->hbmMask
))
716 bResult
= StretchDIBits(hdc
, 0, 0, pdata
->cx
, pdata
->cy
,
718 pvMask
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
) != 0;
722 if(hbmpOld
) SelectObject(hdc
, hbmpOld
);
724 if(pbmiCopy
) HeapFree(GetProcessHeap(), 0, pbmiCopy
);
725 /* Clean up in case of failure */
728 if(pdata
->hbmMask
) DeleteObject(pdata
->hbmMask
);
729 if(pdata
->hbmColor
) DeleteObject(pdata
->hbmColor
);
730 if(pdata
->hbmAlpha
) DeleteObject(pdata
->hbmAlpha
);
735 static BOOL
CURSORICON_GetCursorDataFromIconInfo(
736 _Out_ CURSORDATA
* pCursorData
,
737 _In_ ICONINFO
* pIconInfo
742 ZeroMemory(pCursorData
, sizeof(*pCursorData
));
743 if(pIconInfo
->hbmColor
)
745 /* We must convert the color bitmap to screen format */
746 HDC hdcScreen
, hdcMem
;
749 /* The mask dictates its dimensions */
750 if (!GetObject(pIconInfo
->hbmMask
, sizeof(bm
), &bm
))
752 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
755 hdcMem
= CreateCompatibleDC(hdcScreen
);
761 pCursorData
->hbmColor
= CreateCompatibleBitmap(hdcScreen
, bm
.bmWidth
, bm
.bmHeight
);
763 if (!pCursorData
->hbmColor
)
768 hbmpPrev
= SelectObject(hdcMem
, pCursorData
->hbmColor
);
772 DeleteObject(pCursorData
->hbmColor
);
775 stretch_blt_icon( hdcMem
, bm
.bmWidth
, bm
.bmHeight
, pIconInfo
->hbmColor
);
776 SelectObject(hdcMem
, hbmpPrev
);
779 pCursorData
->hbmMask
= CopyImage(pIconInfo
->hbmMask
, IMAGE_BITMAP
, 0, 0, LR_MONOCHROME
);
780 if(!pCursorData
->hbmMask
)
783 /* Now, fill some information */
784 pCursorData
->rt
= (USHORT
)((ULONG_PTR
)(pIconInfo
->fIcon
? RT_ICON
: RT_CURSOR
));
785 if(pCursorData
->hbmColor
)
787 GetObject(pCursorData
->hbmColor
, sizeof(bm
), &bm
);
788 pCursorData
->bpp
= bm
.bmBitsPixel
;
789 pCursorData
->cx
= bm
.bmWidth
;
790 pCursorData
->cy
= bm
.bmHeight
;
791 if(pCursorData
->bpp
== 32)
792 pCursorData
->hbmAlpha
= create_alpha_bitmap(pCursorData
->hbmColor
, NULL
, NULL
, 0, 0);
796 GetObject(pCursorData
->hbmMask
, sizeof(bm
), &bm
);
797 pCursorData
->bpp
= 1;
798 pCursorData
->cx
= bm
.bmWidth
;
799 pCursorData
->cy
= bm
.bmHeight
/2;
804 pCursorData
->xHotspot
= pCursorData
->cx
/2;
805 pCursorData
->yHotspot
= pCursorData
->cy
/2;
809 pCursorData
->xHotspot
= pIconInfo
->xHotspot
;
810 pCursorData
->yHotspot
= pIconInfo
->yHotspot
;
817 #define RIFF_FOURCC( c0, c1, c2, c3 ) \
818 ( (DWORD)(BYTE)(c0) | ( (DWORD)(BYTE)(c1) << 8 ) | \
819 ( (DWORD)(BYTE)(c2) << 16 ) | ( (DWORD)(BYTE)(c3) << 24 ) )
821 #define ANI_RIFF_ID RIFF_FOURCC('R', 'I', 'F', 'F')
822 #define ANI_LIST_ID RIFF_FOURCC('L', 'I', 'S', 'T')
823 #define ANI_ACON_ID RIFF_FOURCC('A', 'C', 'O', 'N')
824 #define ANI_anih_ID RIFF_FOURCC('a', 'n', 'i', 'h')
825 #define ANI_seq__ID RIFF_FOURCC('s', 'e', 'q', ' ')
826 #define ANI_fram_ID RIFF_FOURCC('f', 'r', 'a', 'm')
827 #define ANI_rate_ID RIFF_FOURCC('r', 'a', 't', 'e')
829 #define ANI_FLAG_ICON 0x1
830 #define ANI_FLAG_SEQUENCE 0x2
832 #include <pshpack1.h>
847 const unsigned char *data
;
851 static void dump_ani_header( const ani_header
*header
)
853 TRACE(" header size: %d\n", header
->header_size
);
854 TRACE(" frames: %d\n", header
->num_frames
);
855 TRACE(" steps: %d\n", header
->num_steps
);
856 TRACE(" width: %d\n", header
->width
);
857 TRACE(" height: %d\n", header
->height
);
858 TRACE(" bpp: %d\n", header
->bpp
);
859 TRACE(" planes: %d\n", header
->num_planes
);
860 TRACE(" display rate: %d\n", header
->display_rate
);
861 TRACE(" flags: 0x%08x\n", header
->flags
);
864 /* Find an animated cursor chunk, given its type and ID */
865 static void riff_find_chunk( DWORD chunk_id
, DWORD chunk_type
, const riff_chunk_t
*parent_chunk
, riff_chunk_t
*chunk
)
867 const unsigned char *ptr
= parent_chunk
->data
;
868 const unsigned char *end
= parent_chunk
->data
+ (parent_chunk
->data_size
- (2 * sizeof(DWORD
)));
870 if (chunk_type
== ANI_LIST_ID
|| chunk_type
== ANI_RIFF_ID
) end
-= sizeof(DWORD
);
874 if ((!chunk_type
&& *(const DWORD
*)ptr
== chunk_id
)
875 || (chunk_type
&& *(const DWORD
*)ptr
== chunk_type
&& *((const DWORD
*)ptr
+ 2) == chunk_id
))
877 ptr
+= sizeof(DWORD
);
878 chunk
->data_size
= (*(const DWORD
*)ptr
+ 1) & ~1;
879 ptr
+= sizeof(DWORD
);
880 if (chunk_type
== ANI_LIST_ID
|| chunk_type
== ANI_RIFF_ID
) ptr
+= sizeof(DWORD
);
886 ptr
+= sizeof(DWORD
);
887 ptr
+= (*(const DWORD
*)ptr
+ 1) & ~1;
888 ptr
+= sizeof(DWORD
);
892 static BOOL
CURSORICON_GetCursorDataFromANI(
893 _Inout_ CURSORDATA
* pCurData
,
894 _In_
const BYTE
*pData
,
895 _In_ DWORD dwDataSize
,
900 const ani_header
*pHeader
;
901 riff_chunk_t root_chunk
= { dwDataSize
, pData
};
902 riff_chunk_t ACON_chunk
= {0};
903 riff_chunk_t anih_chunk
= {0};
904 riff_chunk_t fram_chunk
= {0};
905 riff_chunk_t rate_chunk
= {0};
906 riff_chunk_t seq_chunk
= {0};
907 const unsigned char *icon_chunk
;
908 const unsigned char *icon_data
;
910 /* Find the root chunk */
911 riff_find_chunk( ANI_ACON_ID
, ANI_RIFF_ID
, &root_chunk
, &ACON_chunk
);
912 if (!ACON_chunk
.data
)
914 ERR("Failed to get root chunk.\n");
918 /* Find the header chunk */
919 riff_find_chunk( ANI_anih_ID
, 0, &ACON_chunk
, &anih_chunk
);
920 if (!ACON_chunk
.data
)
922 ERR("Failed to get header chunk.\n");
925 pHeader
= (ani_header
*)anih_chunk
.data
;
926 dump_ani_header(pHeader
);
928 /* Set up the master data */
929 pCurData
->CURSORF_flags
|= CURSORF_ACON
;
930 pCurData
->cpcur
= pHeader
->num_frames
;
931 pCurData
->cicur
= pHeader
->num_steps
;
932 pCurData
->iicur
= pHeader
->display_rate
;
934 /* Get the sequences */
935 if (pHeader
->flags
& ANI_FLAG_SEQUENCE
)
937 riff_find_chunk( ANI_seq__ID
, 0, &ACON_chunk
, &seq_chunk
);
940 ERR("No sequence data although the flag is set!\n");
945 /* Get the frame rates */
946 riff_find_chunk( ANI_rate_ID
, 0, &ACON_chunk
, &rate_chunk
);
948 pCurData
->ajifRate
= (INT
*)rate_chunk
.data
;
950 /* Get the frames chunk */
951 riff_find_chunk( ANI_fram_ID
, ANI_LIST_ID
, &ACON_chunk
, &fram_chunk
);
952 if (!fram_chunk
.data
)
954 ERR("Failed to get icon list.\n");
957 icon_chunk
= fram_chunk
.data
;
958 icon_data
= fram_chunk
.data
+ (2 * sizeof(DWORD
));
960 if(pHeader
->num_frames
> 1)
962 /* Allocate frame descriptors, step indices and rates */
963 pCurData
->aspcur
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
964 pHeader
->num_frames
* sizeof(CURSORDATA
) + pHeader
->num_steps
* (sizeof(DWORD
) + sizeof(INT
)));
965 if(!pCurData
->aspcur
)
967 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
970 pCurData
->aicur
= (DWORD
*)(pCurData
->aspcur
+ pHeader
->num_frames
);
971 pCurData
->ajifRate
= (INT
*)(pCurData
->aicur
+ pHeader
->num_steps
);
974 for(i
=0; i
< pHeader
->num_frames
; i
++)
976 CURSORDATA
* pFrameData
;
977 const DWORD chunk_size
= *(const DWORD
*)(icon_chunk
+ sizeof(DWORD
));
978 const BITMAPINFO
* pbmi
;
980 if(pHeader
->num_frames
> 1)
981 pFrameData
= &pCurData
->aspcur
[i
];
983 pFrameData
= pCurData
;
985 pFrameData
->rt
= pCurData
->rt
;
987 if (pHeader
->flags
& ANI_FLAG_ICON
)
989 /* The chunks describe an icon file */
990 const CURSORICONFILEDIRENTRY
* pDirEntry
= get_best_icon_file_entry(
991 (const CURSORICONFILEDIR
*) icon_data
,
999 ERR("Unable to find the right file entry for frame %d.\n", i
);
1002 pFrameData
->xHotspot
= pDirEntry
->xHotspot
;
1003 pFrameData
->yHotspot
= pDirEntry
->yHotspot
;
1004 if(!pHeader
->width
|| !pHeader
->height
)
1006 pFrameData
->cx
= pDirEntry
->bWidth
;
1007 pFrameData
->cy
= pDirEntry
->bHeight
;
1011 pFrameData
->cx
= pHeader
->width
;
1012 pFrameData
->cy
= pHeader
->height
;
1014 pbmi
= (const BITMAPINFO
*) (icon_data
+ pDirEntry
->dwDIBOffset
);
1018 /* The chunks just describe bitmaps */
1019 pbmi
= (const BITMAPINFO
*)icon_data
;
1020 pFrameData
->xHotspot
= pFrameData
->yHotspot
= 0;
1023 /* Do the real work */
1024 CURSORICON_GetCursorDataFromBMI(pFrameData
, pbmi
);
1026 if(pHeader
->num_frames
> 1)
1027 pFrameData
->CURSORF_flags
|= CURSORF_ACONFRAME
;
1029 pFrameData
->CURSORF_flags
&= ~CURSORF_ACON
;
1033 icon_chunk
+= chunk_size
+ (2 * sizeof(DWORD
));
1034 icon_data
= icon_chunk
+ (2 * sizeof(DWORD
));
1037 if(pHeader
->num_frames
<= 1)
1041 CopyMemory(pCurData
->ajifRate
, rate_chunk
.data
, pHeader
->num_steps
* sizeof(INT
));
1044 for(i
=0; i
< pHeader
->num_steps
; i
++)
1045 pCurData
->ajifRate
[i
] = pHeader
->display_rate
;
1048 if (pHeader
->flags
& ANI_FLAG_SEQUENCE
)
1050 CopyMemory(pCurData
->aicur
, seq_chunk
.data
, pHeader
->num_steps
* sizeof(DWORD
));
1054 for(i
=0; i
< pHeader
->num_steps
; i
++)
1055 pCurData
->aicur
[i
] = i
;
1061 HeapFree(GetProcessHeap(), 0, pCurData
->aspcur
);
1062 ZeroMemory(pCurData
, sizeof(CURSORDATA
));
1070 _In_opt_ HINSTANCE hinst
,
1071 _In_ LPCWSTR lpszName
,
1077 const BITMAPINFO
* pbmi
;
1078 BITMAPINFO
* pbmiScaled
= NULL
;
1079 BITMAPINFO
* pbmiCopy
= NULL
;
1080 const VOID
* pvMapping
= NULL
;
1082 HGLOBAL hgRsrc
= NULL
;
1085 HDC hdcScreen
= NULL
;
1087 HBITMAP hbmpOld
, hbmpRet
= NULL
;
1092 /* Map the bitmap info */
1093 if(fuLoad
& LR_LOADFROMFILE
)
1095 const BITMAPFILEHEADER
* pbmfh
;
1097 pvMapping
= map_fileW(lpszName
, NULL
);
1101 if (pbmfh
->bfType
!= 0x4d42 /* 'BM' */)
1103 WARN("Invalid/unsupported bitmap format!\n");
1106 pbmi
= (const BITMAPINFO
*)(pbmfh
+ 1);
1108 /* Get the image bits */
1109 if(pbmfh
->bfOffBits
)
1110 dwOffset
= pbmfh
->bfOffBits
- sizeof(BITMAPFILEHEADER
);
1116 /* Caller wants an OEM bitmap */
1118 hinst
= User32Instance
;
1119 hrsrc
= FindResourceW(hinst
, lpszName
, RT_BITMAP
);
1122 hgRsrc
= LoadResource(hinst
, hrsrc
);
1125 pbmi
= LockResource(hgRsrc
);
1131 if(DIB_GetBitmapInfo(&pbmi
->bmiHeader
, &width
, &height
, &bpp
, &compr
) == -1)
1133 if((width
> 65535) || (height
> 65535))
1140 cyDesired
= -cyDesired
;
1142 iBMISize
= bitmap_info_size(pbmi
, DIB_RGB_COLORS
);
1144 /* Get a pointer to the image data */
1145 pvBits
= (char*)pbmi
+ (dwOffset
? dwOffset
: iBMISize
);
1147 /* Create a copy of the info describing the bitmap in the file */
1148 pbmiCopy
= HeapAlloc(GetProcessHeap(), 0, iBMISize
);
1151 CopyMemory(pbmiCopy
, pbmi
, iBMISize
);
1153 /* Fix it up, if needed */
1154 if(fuLoad
& (LR_LOADTRANSPARENT
| LR_LOADMAP3DCOLORS
))
1156 WORD bpp
, incr
, numColors
;
1159 COLORREF crWindow
, cr3DShadow
, cr3DFace
, cr3DLight
;
1160 BYTE pixel
= *((BYTE
*)pvBits
);
1163 if(pbmiCopy
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
1165 bpp
= ((BITMAPCOREHEADER
*)&pbmiCopy
->bmiHeader
)->bcBitCount
;
1166 numColors
= 1 << bpp
;
1167 /* BITMAPCOREINFO holds RGBTRIPLEs */
1172 bpp
= pbmiCopy
->bmiHeader
.biBitCount
;
1173 /* BITMAPINFOHEADER holds RGBQUADs */
1175 numColors
= pbmiCopy
->bmiHeader
.biClrUsed
;
1176 if(numColors
> 256) numColors
= 256;
1177 if (!numColors
&& (bpp
<= 8)) numColors
= 1 << bpp
;
1183 pbmiColors
= (char*)pbmiCopy
+ pbmiCopy
->bmiHeader
.biSize
;
1185 /* Get the relevant colors */
1186 crWindow
= GetSysColor(COLOR_WINDOW
);
1187 cr3DShadow
= GetSysColor(COLOR_3DSHADOW
);
1188 cr3DFace
= GetSysColor(COLOR_3DFACE
);
1189 cr3DLight
= GetSysColor(COLOR_3DLIGHT
);
1191 /* Fix the transparent palette entry */
1192 if(fuLoad
& LR_LOADTRANSPARENT
)
1196 case 1: pixel
>>= 7; break;
1197 case 4: pixel
>>= 4; break;
1200 FIXME("Unhandled bit depth %d.\n", bpp
);
1204 if(pixel
>= numColors
)
1206 ERR("Wrong pixel passed in.\n");
1210 /* If both flags are set, we must use COLOR_3DFACE */
1211 if(fuLoad
& LR_LOADMAP3DCOLORS
) crWindow
= cr3DFace
;
1213 /* Define the color */
1214 ptr
= (RGBTRIPLE
*)(pbmiColors
+ pixel
*incr
);
1215 ptr
->rgbtBlue
= GetBValue(crWindow
);
1216 ptr
->rgbtGreen
= GetGValue(crWindow
);
1217 ptr
->rgbtRed
= GetRValue(crWindow
);
1221 /* If we are here, then LR_LOADMAP3DCOLORS is set without LR_TRANSPARENT */
1222 for(i
= 0; i
<numColors
; i
++)
1224 ptr
= (RGBTRIPLE
*)(pbmiColors
+ i
*incr
);
1225 if((ptr
->rgbtBlue
== ptr
->rgbtRed
) && (ptr
->rgbtBlue
== ptr
->rgbtGreen
))
1227 if(ptr
->rgbtBlue
== 128)
1229 ptr
->rgbtBlue
= GetBValue(cr3DShadow
);
1230 ptr
->rgbtGreen
= GetGValue(cr3DShadow
);
1231 ptr
->rgbtRed
= GetRValue(cr3DShadow
);
1233 if(ptr
->rgbtBlue
== 192)
1235 ptr
->rgbtBlue
= GetBValue(cr3DFace
);
1236 ptr
->rgbtGreen
= GetGValue(cr3DFace
);
1237 ptr
->rgbtRed
= GetRValue(cr3DFace
);
1239 if(ptr
->rgbtBlue
== 223)
1241 ptr
->rgbtBlue
= GetBValue(cr3DLight
);
1242 ptr
->rgbtGreen
= GetGValue(cr3DLight
);
1243 ptr
->rgbtRed
= GetRValue(cr3DLight
);
1250 if(fuLoad
& LR_CREATEDIBSECTION
)
1252 /* Allocate the BMI describing the new bitmap */
1253 pbmiScaled
= HeapAlloc(GetProcessHeap(), 0, iBMISize
);
1256 CopyMemory(pbmiScaled
, pbmiCopy
, iBMISize
);
1259 if(pbmiScaled
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
1261 BITMAPCOREHEADER
* pbmch
= (BITMAPCOREHEADER
*)&pbmiScaled
->bmiHeader
;
1262 pbmch
->bcWidth
= cxDesired
;
1263 pbmch
->bcHeight
= cyDesired
;
1267 pbmiScaled
->bmiHeader
.biWidth
= cxDesired
;
1268 pbmiScaled
->bmiHeader
.biHeight
= cyDesired
;
1269 /* No compression for DIB sections */
1270 pbmiScaled
->bmiHeader
.biCompression
= BI_RGB
;
1274 /* Top-down image */
1275 if(cyDesired
< 0) cyDesired
= -cyDesired
;
1277 /* We need a device context */
1278 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
1281 hdc
= CreateCompatibleDC(hdcScreen
);
1285 /* Now create the bitmap */
1286 if(fuLoad
& LR_CREATEDIBSECTION
)
1287 hbmpRet
= CreateDIBSection(hdc
, pbmiScaled
, DIB_RGB_COLORS
, NULL
, 0, 0);
1290 if(is_dib_monochrome(pbmiCopy
) || (fuLoad
& LR_MONOCHROME
))
1291 hbmpRet
= CreateBitmap(cxDesired
, cyDesired
, 1, 1, NULL
);
1293 hbmpRet
= CreateCompatibleBitmap(hdcScreen
, cxDesired
, cyDesired
);
1299 hbmpOld
= SelectObject(hdc
, hbmpRet
);
1302 if(!StretchDIBits(hdc
, 0, 0, cxDesired
, cyDesired
,
1303 0, 0, width
, height
,
1304 pvBits
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
))
1306 ERR("StretchDIBits failed!.\n");
1307 SelectObject(hdc
, hbmpOld
);
1308 DeleteObject(hbmpRet
);
1313 SelectObject(hdc
, hbmpOld
);
1317 DeleteDC(hdcScreen
);
1321 HeapFree(GetProcessHeap(), 0, pbmiScaled
);
1323 HeapFree(GetProcessHeap(), 0, pbmiCopy
);
1325 UnmapViewOfFile( pvMapping
);
1327 FreeResource(hgRsrc
);
1335 CURSORICON_LoadFromFileW(
1336 _In_ LPCWSTR lpszName
,
1343 const CURSORICONFILEDIRENTRY
*entry
;
1344 const CURSORICONFILEDIR
*dir
;
1347 HANDLE hCurIcon
= NULL
;
1348 CURSORDATA cursorData
;
1350 TRACE("loading %s\n", debugstr_w( lpszName
));
1352 bits
= map_fileW( lpszName
, &filesize
);
1356 /* Check for .ani. */
1357 if (memcmp( bits
, "RIFF", 4 ) == 0)
1363 dir
= (CURSORICONFILEDIR
*) bits
;
1364 entry
= get_best_icon_file_entry(dir
, filesize
, cxDesired
, cyDesired
, bIcon
, fuLoad
);
1368 /* Fix dimensions */
1369 if(!cxDesired
) cxDesired
= entry
->bWidth
;
1370 if(!cyDesired
) cyDesired
= entry
->bHeight
;
1371 /* A bit of preparation */
1372 ZeroMemory(&cursorData
, sizeof(cursorData
));
1375 cursorData
.xHotspot
= entry
->xHotspot
;
1376 cursorData
.yHotspot
= entry
->yHotspot
;
1378 cursorData
.rt
= (USHORT
)((ULONG_PTR
)(bIcon
? RT_ICON
: RT_CURSOR
));
1381 if(!CURSORICON_GetCursorDataFromBMI(&cursorData
, (BITMAPINFO
*)(&bits
[entry
->dwDIBOffset
])))
1384 hCurIcon
= NtUserxCreateEmptyCurObject(FALSE
);
1389 if(!NtUserSetCursorIconData(hCurIcon
, NULL
, NULL
, &cursorData
))
1391 NtUserDestroyCursor(hCurIcon
, TRUE
);
1396 UnmapViewOfFile(bits
);
1401 DeleteObject(cursorData
.hbmMask
);
1402 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
1403 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
1404 UnmapViewOfFile(bits
);
1411 CURSORICON_LoadImageW(
1412 _In_opt_ HINSTANCE hinst
,
1413 _In_ LPCWSTR lpszName
,
1421 HANDLE handle
, hCurIcon
= NULL
;
1425 CURSORDATA cursorData
;
1427 UNICODE_STRING ustrRsrc
;
1428 UNICODE_STRING ustrModule
= {0, 0, NULL
};
1430 /* Fix width/height */
1431 if(fuLoad
& LR_DEFAULTSIZE
)
1433 if(!cxDesired
) cxDesired
= GetSystemMetrics(bIcon
? SM_CXICON
: SM_CXCURSOR
);
1434 if(!cyDesired
) cyDesired
= GetSystemMetrics(bIcon
? SM_CYICON
: SM_CYCURSOR
);
1437 if(fuLoad
& LR_LOADFROMFILE
)
1439 return CURSORICON_LoadFromFileW(lpszName
, cxDesired
, cyDesired
, fuLoad
, bIcon
);
1442 /* Check if caller wants OEM icons */
1444 hinst
= User32Instance
;
1448 /* Prepare the resource name string */
1449 if(IS_INTRESOURCE(lpszName
))
1451 ustrRsrc
.Buffer
= (LPWSTR
)lpszName
;
1452 ustrRsrc
.Length
= 0;
1453 ustrRsrc
.MaximumLength
= 0;
1456 RtlInitUnicodeString(&ustrRsrc
, lpszName
);
1461 DWORD size
= MAX_PATH
;
1462 /* Get the module name string */
1466 ustrModule
.Buffer
= HeapAlloc(GetProcessHeap(), 0, size
*sizeof(WCHAR
));
1467 if (!ustrModule
.Buffer
)
1469 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1472 ret
= GetModuleFileNameW(hinst
, ustrModule
.Buffer
, size
);
1475 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1479 /* This API is completely broken... */
1482 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1487 ustrModule
.Buffer
[ret
] = UNICODE_NULL
;
1488 ustrModule
.Length
= ret
* sizeof(WCHAR
);
1489 ustrModule
.MaximumLength
= size
* sizeof(WCHAR
);
1494 if(fuLoad
& LR_SHARED
)
1496 FINDEXISTINGCURICONPARAM param
;
1498 TRACE("Checking for an LR_SHARED cursor/icon.\n");
1500 param
.bIcon
= bIcon
;
1501 param
.cx
= cxDesired
;
1502 param
.cy
= cyDesired
;
1503 hCurIcon
= NtUserFindExistingCursorIcon(&ustrModule
, &ustrRsrc
, ¶m
);
1506 /* Woohoo, got it! */
1507 TRACE("MATCH! %p\n",hCurIcon
);
1508 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1513 /* Find resource ID */
1514 hrsrc
= FindResourceW(
1517 bIcon
? RT_GROUP_ICON
: RT_GROUP_CURSOR
);
1519 /* We let FindResource, LoadResource, etc. call SetLastError */
1523 handle
= LoadResource(hinst
, hrsrc
);
1527 dir
= LockResource(handle
);
1531 wResId
= LookupIconIdFromDirectoryEx((PBYTE
)dir
, bIcon
, cxDesired
, cyDesired
, fuLoad
);
1532 FreeResource(handle
);
1534 /* Get the relevant resource pointer */
1535 hrsrc
= FindResourceW(
1537 MAKEINTRESOURCEW(wResId
),
1538 bIcon
? RT_ICON
: RT_CURSOR
);
1542 handle
= LoadResource(hinst
, hrsrc
);
1546 bits
= LockResource(handle
);
1549 FreeResource(handle
);
1553 ZeroMemory(&cursorData
, sizeof(cursorData
));
1555 /* This is from resource */
1556 cursorData
.CURSORF_flags
= CURSORF_FROMRESOURCE
;
1558 if(dir
->idType
== 2)
1560 /* idType == 2 for cursor resources */
1561 SHORT
* ptr
= (SHORT
*)bits
;
1562 cursorData
.xHotspot
= ptr
[0];
1563 cursorData
.yHotspot
= ptr
[1];
1564 bits
+= 2*sizeof(SHORT
);
1566 cursorData
.cx
= cxDesired
;
1567 cursorData
.cy
= cyDesired
;
1568 cursorData
.rt
= (USHORT
)((ULONG_PTR
)(bIcon
? RT_ICON
: RT_CURSOR
));
1570 /* Get the bitmaps */
1571 bStatus
= CURSORICON_GetCursorDataFromBMI(
1575 FreeResource( handle
);
1580 /* Create the handle */
1581 hCurIcon
= NtUserxCreateEmptyCurObject(FALSE
);
1587 if(fuLoad
& LR_SHARED
)
1589 cursorData
.CURSORF_flags
|= CURSORF_LRSHARED
;
1593 bStatus
= NtUserSetCursorIconData(hCurIcon
, hinst
? &ustrModule
: NULL
, lpszName
? &ustrRsrc
: NULL
, &cursorData
);
1597 NtUserDestroyCursor(hCurIcon
, TRUE
);
1602 if(ustrModule
.Buffer
)
1603 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1607 if(ustrModule
.Buffer
)
1608 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1609 DeleteObject(cursorData
.hbmMask
);
1610 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
1611 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
1630 objSize
= GetObjectW( hnd
, sizeof(ds
), &ds
);
1631 if (!objSize
) return 0;
1632 if ((desiredx
< 0) || (desiredy
< 0)) return 0;
1634 if (flags
& LR_COPYFROMRESOURCE
)
1636 FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
1639 if (flags
& LR_COPYRETURNORG
)
1641 FIXME("The flag LR_COPYRETURNORG is not implemented for bitmaps\n");
1644 if (desiredx
== 0) desiredx
= ds
.dsBm
.bmWidth
;
1645 if (desiredy
== 0) desiredy
= ds
.dsBm
.bmHeight
;
1647 /* Allocate memory for a BITMAPINFOHEADER structure and a
1648 color table. The maximum number of colors in a color table
1649 is 256 which corresponds to a bitmap with depth 8.
1650 Bitmaps with higher depths don't have color tables. */
1651 bi
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
));
1654 bi
->bmiHeader
.biSize
= sizeof(bi
->bmiHeader
);
1655 bi
->bmiHeader
.biPlanes
= ds
.dsBm
.bmPlanes
;
1656 bi
->bmiHeader
.biBitCount
= ds
.dsBm
.bmBitsPixel
;
1657 bi
->bmiHeader
.biCompression
= BI_RGB
;
1659 if (flags
& LR_CREATEDIBSECTION
)
1661 /* Create a DIB section. LR_MONOCHROME is ignored */
1663 HDC dc
= CreateCompatibleDC(NULL
);
1665 if (objSize
== sizeof(DIBSECTION
))
1667 /* The source bitmap is a DIB.
1668 Get its attributes to create an exact copy */
1669 memcpy(bi
, &ds
.dsBmih
, sizeof(BITMAPINFOHEADER
));
1672 bi
->bmiHeader
.biWidth
= desiredx
;
1673 bi
->bmiHeader
.biHeight
= desiredy
;
1675 /* Get the color table or the color masks */
1676 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
1678 res
= CreateDIBSection(dc
, bi
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
1683 /* Create a device-dependent bitmap */
1685 BOOL monochrome
= (flags
& LR_MONOCHROME
);
1687 if (objSize
== sizeof(DIBSECTION
))
1689 /* The source bitmap is a DIB section.
1690 Get its attributes */
1691 HDC dc
= CreateCompatibleDC(NULL
);
1692 bi
->bmiHeader
.biWidth
= ds
.dsBm
.bmWidth
;
1693 bi
->bmiHeader
.biHeight
= ds
.dsBm
.bmHeight
;
1694 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
1697 if (!monochrome
&& ds
.dsBm
.bmBitsPixel
== 1)
1699 /* Look if the colors of the DIB are black and white */
1702 (bi
->bmiColors
[0].rgbRed
== 0xff
1703 && bi
->bmiColors
[0].rgbGreen
== 0xff
1704 && bi
->bmiColors
[0].rgbBlue
== 0xff
1705 && bi
->bmiColors
[0].rgbReserved
== 0
1706 && bi
->bmiColors
[1].rgbRed
== 0
1707 && bi
->bmiColors
[1].rgbGreen
== 0
1708 && bi
->bmiColors
[1].rgbBlue
== 0
1709 && bi
->bmiColors
[1].rgbReserved
== 0)
1711 (bi
->bmiColors
[0].rgbRed
== 0
1712 && bi
->bmiColors
[0].rgbGreen
== 0
1713 && bi
->bmiColors
[0].rgbBlue
== 0
1714 && bi
->bmiColors
[0].rgbReserved
== 0
1715 && bi
->bmiColors
[1].rgbRed
== 0xff
1716 && bi
->bmiColors
[1].rgbGreen
== 0xff
1717 && bi
->bmiColors
[1].rgbBlue
== 0xff
1718 && bi
->bmiColors
[1].rgbReserved
== 0);
1721 else if (!monochrome
)
1723 monochrome
= ds
.dsBm
.bmBitsPixel
== 1;
1728 res
= CreateBitmap(desiredx
, desiredy
, 1, 1, NULL
);
1732 HDC screenDC
= GetDC(NULL
);
1733 res
= CreateCompatibleBitmap(screenDC
, desiredx
, desiredy
);
1734 ReleaseDC(NULL
, screenDC
);
1740 /* Only copy the bitmap if it's a DIB section or if it's
1741 compatible to the screen */
1744 if (objSize
== sizeof(DIBSECTION
))
1746 copyContents
= TRUE
;
1750 HDC screenDC
= GetDC(NULL
);
1751 int screen_depth
= GetDeviceCaps(screenDC
, BITSPIXEL
);
1752 ReleaseDC(NULL
, screenDC
);
1754 copyContents
= (ds
.dsBm
.bmBitsPixel
== 1 || ds
.dsBm
.bmBitsPixel
== screen_depth
);
1759 /* The source bitmap may already be selected in a device context,
1760 use GetDIBits/StretchDIBits and not StretchBlt */
1765 dc
= CreateCompatibleDC(NULL
);
1767 bi
->bmiHeader
.biWidth
= ds
.dsBm
.bmWidth
;
1768 bi
->bmiHeader
.biHeight
= ds
.dsBm
.bmHeight
;
1769 bi
->bmiHeader
.biSizeImage
= 0;
1770 bi
->bmiHeader
.biClrUsed
= 0;
1771 bi
->bmiHeader
.biClrImportant
= 0;
1773 /* Fill in biSizeImage */
1774 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
1775 bits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, bi
->bmiHeader
.biSizeImage
);
1781 /* Get the image bits of the source bitmap */
1782 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, bits
, bi
, DIB_RGB_COLORS
);
1784 /* Copy it to the destination bitmap */
1785 oldBmp
= SelectObject(dc
, res
);
1786 StretchDIBits(dc
, 0, 0, desiredx
, desiredy
,
1787 0, 0, ds
.dsBm
.bmWidth
, ds
.dsBm
.bmHeight
,
1788 bits
, bi
, DIB_RGB_COLORS
, SRCCOPY
);
1789 SelectObject(dc
, oldBmp
);
1791 HeapFree(GetProcessHeap(), 0, bits
);
1797 if (flags
& LR_COPYDELETEORG
)
1802 HeapFree(GetProcessHeap(), 0, bi
);
1808 CURSORICON_CopyImage(
1818 CURSORDATA CursorData
;
1820 if (fuFlags
& LR_COPYFROMRESOURCE
)
1822 /* Get the icon module/resource names */
1823 UNICODE_STRING ustrModule
;
1824 UNICODE_STRING ustrRsrc
;
1827 ustrModule
.MaximumLength
= 0;
1828 ustrRsrc
.MaximumLength
= 0;
1830 /* Get the buffer size */
1831 if (!NtUserGetIconInfo(hicon
, NULL
, &ustrModule
, &ustrRsrc
, NULL
, FALSE
))
1836 ustrModule
.Buffer
= HeapAlloc(GetProcessHeap(), 0, ustrModule
.MaximumLength
);
1837 if (!ustrModule
.Buffer
)
1839 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1843 if (ustrRsrc
.MaximumLength
)
1845 ustrRsrc
.Buffer
= HeapAlloc(GetProcessHeap(), 0, ustrRsrc
.MaximumLength
);
1846 if (!ustrRsrc
.Buffer
)
1848 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1849 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1854 if (!NtUserGetIconInfo(hicon
, NULL
, &ustrModule
, &ustrRsrc
, NULL
, FALSE
))
1856 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1857 if (!IS_INTRESOURCE(ustrRsrc
.Buffer
))
1858 HeapFree(GetProcessHeap(), 0, ustrRsrc
.Buffer
);
1862 /* NULL-terminate our strings */
1863 ustrModule
.Buffer
[ustrModule
.Length
/sizeof(WCHAR
)] = UNICODE_NULL
;
1864 if (!IS_INTRESOURCE(ustrRsrc
.Buffer
))
1865 ustrRsrc
.Buffer
[ustrRsrc
.Length
/sizeof(WCHAR
)] = UNICODE_NULL
;
1867 TRACE("Got module %wZ, resource %p (%S).\n", &ustrModule
,
1868 ustrRsrc
.Buffer
, IS_INTRESOURCE(ustrRsrc
.Buffer
) ? L
"" : ustrRsrc
.Buffer
);
1870 /* Get the module handle or load the module */
1871 hModule
= LoadLibraryExW(ustrModule
.Buffer
, NULL
, LOAD_LIBRARY_AS_IMAGE_RESOURCE
| LOAD_LIBRARY_AS_DATAFILE
);
1874 DWORD err
= GetLastError();
1875 ERR("Unable to load/use module '%wZ' in process %lu, error %lu.\n", &ustrModule
, GetCurrentProcessId(), err
);
1876 SetLastError(ERROR_INVALID_PARAMETER
);
1880 /* Call the relevant function */
1881 ret
= CURSORICON_LoadImageW(
1886 fuFlags
& (LR_DEFAULTSIZE
| LR_SHARED
),
1889 FreeLibrary(hModule
);
1891 /* If we're here, that means that the passed icon is shared. Don't destroy it, even if LR_COPYDELETEORG is specified */
1893 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1894 if (!IS_INTRESOURCE(ustrRsrc
.Buffer
))
1895 HeapFree(GetProcessHeap(), 0, ustrRsrc
.Buffer
);
1897 TRACE("Returning 0x%08x.\n", ret
);
1902 /* This is a regular copy */
1903 if (fuFlags
& ~(LR_COPYDELETEORG
| LR_SHARED
))
1904 FIXME("Unimplemented flags: 0x%08x\n", fuFlags
);
1906 if (!GetIconInfo(hicon
, &ii
))
1908 ERR("GetIconInfo failed.\n");
1912 /* This is CreateIconIndirect with the LR_SHARED coat added */
1913 if (!CURSORICON_GetCursorDataFromIconInfo(&CursorData
, &ii
))
1916 if (fuFlags
& LR_SHARED
)
1917 CursorData
.CURSORF_flags
|= CURSORF_LRSHARED
;
1919 ret
= NtUserxCreateEmptyCurObject(FALSE
);
1923 if (!NtUserSetCursorIconData(ret
, NULL
, NULL
, &CursorData
))
1925 NtUserDestroyCursor(ret
, TRUE
);
1930 DeleteObject(ii
.hbmMask
);
1931 if (ii
.hbmColor
) DeleteObject(ii
.hbmColor
);
1933 if (ret
&& (fuFlags
& LR_COPYDELETEORG
))
1940 User32CallCopyImageFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
1942 PCOPYIMAGE_CALLBACK_ARGUMENTS Common
;
1944 Common
= (PCOPYIMAGE_CALLBACK_ARGUMENTS
) Arguments
;
1946 Result
= CopyImage(Common
->hImage
,
1952 return ZwCallbackReturn(&Result
, sizeof(HANDLE
), STATUS_SUCCESS
);
1956 /************* PUBLIC FUNCTIONS *******************/
1958 HANDLE WINAPI
CopyImage(
1966 TRACE("hImage=%p, uType=%u, cxDesired=%d, cyDesired=%d, fuFlags=%x\n",
1967 hImage
, uType
, cxDesired
, cyDesired
, fuFlags
);
1971 return BITMAP_CopyImage(hImage
, cxDesired
, cyDesired
, fuFlags
);
1974 return CURSORICON_CopyImage(hImage
, uType
== IMAGE_ICON
, cxDesired
, cyDesired
, fuFlags
);
1976 SetLastError(ERROR_INVALID_PARAMETER
);
1982 HICON WINAPI
CopyIcon(
1986 return CURSORICON_CopyImage(hIcon
, FALSE
, 0, 0, 0);
1989 BOOL WINAPI
DrawIcon(
1996 return DrawIconEx(hDC
, X
, Y
, hIcon
, 0, 0, 0, NULL
, DI_NORMAL
| DI_COMPAT
| DI_DEFAULTSIZE
);
1999 BOOL WINAPI
DrawIconEx(
2006 _In_ UINT istepIfAniCur
,
2007 _In_opt_ HBRUSH hbrFlickerFreeDraw
,
2011 return NtUserDrawIconEx(hdc
, xLeft
, yTop
, hIcon
, cxWidth
, cyWidth
,
2012 istepIfAniCur
, hbrFlickerFreeDraw
, diFlags
,
2016 BOOL WINAPI
GetIconInfo(
2018 _Out_ PICONINFO piconinfo
2021 return NtUserGetIconInfo(hIcon
, piconinfo
, NULL
, NULL
, NULL
, FALSE
);
2024 BOOL WINAPI
DestroyIcon(
2028 return NtUserDestroyCursor(hIcon
, FALSE
);
2031 HICON WINAPI
LoadIconA(
2032 _In_opt_ HINSTANCE hInstance
,
2033 _In_ LPCSTR lpIconName
2036 TRACE("%p, %s\n", hInstance
, debugstr_a(lpIconName
));
2038 return LoadImageA(hInstance
,
2043 LR_SHARED
| LR_DEFAULTSIZE
);
2046 HICON WINAPI
LoadIconW(
2047 _In_opt_ HINSTANCE hInstance
,
2048 _In_ LPCWSTR lpIconName
2051 TRACE("%p, %s\n", hInstance
, debugstr_w(lpIconName
));
2053 return LoadImageW(hInstance
,
2058 LR_SHARED
| LR_DEFAULTSIZE
);
2061 HCURSOR WINAPI
LoadCursorA(
2062 _In_opt_ HINSTANCE hInstance
,
2063 _In_ LPCSTR lpCursorName
2066 TRACE("%p, %s\n", hInstance
, debugstr_a(lpCursorName
));
2068 return LoadImageA(hInstance
,
2073 LR_SHARED
| LR_DEFAULTSIZE
);
2076 HCURSOR WINAPI
LoadCursorW(
2077 _In_opt_ HINSTANCE hInstance
,
2078 _In_ LPCWSTR lpCursorName
2081 TRACE("%p, %s\n", hInstance
, debugstr_w(lpCursorName
));
2083 return LoadImageW(hInstance
,
2088 LR_SHARED
| LR_DEFAULTSIZE
);
2091 HCURSOR WINAPI
LoadCursorFromFileA(
2092 _In_ LPCSTR lpFileName
2095 TRACE("%s\n", debugstr_a(lpFileName
));
2097 return LoadImageA(NULL
,
2102 LR_LOADFROMFILE
| LR_DEFAULTSIZE
);
2105 HCURSOR WINAPI
LoadCursorFromFileW(
2106 _In_ LPCWSTR lpFileName
2109 TRACE("%s\n", debugstr_w(lpFileName
));
2111 return LoadImageW(NULL
,
2116 LR_LOADFROMFILE
| LR_DEFAULTSIZE
);
2119 HBITMAP WINAPI
LoadBitmapA(
2120 _In_opt_ HINSTANCE hInstance
,
2121 _In_ LPCSTR lpBitmapName
2124 TRACE("%p, %s\n", hInstance
, debugstr_a(lpBitmapName
));
2126 return LoadImageA(hInstance
,
2134 HBITMAP WINAPI
LoadBitmapW(
2135 _In_opt_ HINSTANCE hInstance
,
2136 _In_ LPCWSTR lpBitmapName
2139 TRACE("%p, %s\n", hInstance
, debugstr_w(lpBitmapName
));
2141 return LoadImageW(hInstance
,
2149 HANDLE WINAPI
LoadImageA(
2150 _In_opt_ HINSTANCE hinst
,
2151 _In_ LPCSTR lpszName
,
2162 if (IS_INTRESOURCE(lpszName
))
2163 return LoadImageW(hinst
, (LPCWSTR
)lpszName
, uType
, cxDesired
, cyDesired
, fuLoad
);
2165 len
= MultiByteToWideChar( CP_ACP
, 0, lpszName
, -1, NULL
, 0 );
2166 u_name
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
2167 MultiByteToWideChar( CP_ACP
, 0, lpszName
, -1, u_name
, len
);
2169 res
= LoadImageW(hinst
, u_name
, uType
, cxDesired
, cyDesired
, fuLoad
);
2170 HeapFree(GetProcessHeap(), 0, u_name
);
2174 HANDLE WINAPI
LoadImageW(
2175 _In_opt_ HINSTANCE hinst
,
2176 _In_ LPCWSTR lpszName
,
2183 TRACE("hinst 0x%p, name %s, uType 0x%08x, cxDesired %d, cyDesired %d, fuLoad 0x%08x.\n",
2184 hinst
, debugstr_w(lpszName
), uType
, cxDesired
, cyDesired
, fuLoad
);
2185 /* Redirect to each implementation */
2189 return BITMAP_LoadImageW(hinst
, lpszName
, cxDesired
, cyDesired
, fuLoad
);
2192 return CURSORICON_LoadImageW(hinst
, lpszName
, cxDesired
, cyDesired
, fuLoad
, uType
== IMAGE_ICON
);
2194 SetLastError(ERROR_INVALID_PARAMETER
);
2200 int WINAPI
LookupIconIdFromDirectory(
2201 _In_ PBYTE presbits
,
2205 return LookupIconIdFromDirectoryEx( presbits
, fIcon
,
2206 fIcon
? GetSystemMetrics(SM_CXICON
) : GetSystemMetrics(SM_CXCURSOR
),
2207 fIcon
? GetSystemMetrics(SM_CYICON
) : GetSystemMetrics(SM_CYCURSOR
), fIcon
? 0 : LR_MONOCHROME
);
2210 int WINAPI
LookupIconIdFromDirectoryEx(
2211 _In_ PBYTE presbits
,
2219 CURSORICONDIR
* dir
= (CURSORICONDIR
*)presbits
;
2220 CURSORICONDIRENTRY
* entry
;
2221 int i
, numMatch
= 0, iIndex
= -1;
2222 WORD width
, height
, BitCount
= 0;
2223 BOOL notPaletted
= FALSE
;
2224 ULONG bestScore
= 0xFFFFFFFF, score
;
2226 TRACE("%p, %x, %i, %i, %x.\n", presbits
, fIcon
, cxDesired
, cyDesired
, Flags
);
2228 if(!(dir
&& !dir
->idReserved
&& (dir
->idType
& 3)))
2230 WARN("Invalid resource.\n");
2234 if(Flags
& LR_MONOCHROME
)
2239 icScreen
= CreateICW(DISPLAYW
, NULL
, NULL
, NULL
);
2243 bppDesired
= GetDeviceCaps(icScreen
, BITSPIXEL
);
2248 cxDesired
= Flags
& LR_DEFAULTSIZE
? GetSystemMetrics(fIcon
? SM_CXICON
: SM_CXCURSOR
) : 256;
2250 cyDesired
= Flags
& LR_DEFAULTSIZE
? GetSystemMetrics(fIcon
? SM_CYICON
: SM_CYCURSOR
) : 256;
2252 /* Find the best match for the desired size */
2253 for(i
= 0; i
< dir
->idCount
; i
++)
2255 entry
= &dir
->idEntries
[i
];
2256 width
= fIcon
? entry
->ResInfo
.icon
.bWidth
: entry
->ResInfo
.cursor
.wWidth
;
2257 /* Height is twice as big in cursor resources */
2258 height
= fIcon
? entry
->ResInfo
.icon
.bHeight
: entry
->ResInfo
.cursor
.wHeight
/2;
2259 /* 0 represents 256 */
2260 if(!width
) width
= 256;
2261 if(!height
) height
= 256;
2262 /* Calculate the "score" (lower is better) */
2263 score
= 2*(abs(width
- cxDesired
) + abs(height
- cyDesired
));
2264 if( score
> bestScore
)
2266 /* Bigger than requested lowers the score */
2267 if(width
> cxDesired
)
2268 score
-= width
- cxDesired
;
2269 if(height
> cyDesired
)
2270 score
-= height
- cyDesired
;
2271 if(score
> bestScore
)
2273 if(score
== bestScore
)
2275 if(entry
->wBitCount
> BitCount
)
2276 BitCount
= entry
->wBitCount
;
2283 BitCount
= entry
->wBitCount
;
2288 /* Only one entry fits the asked dimensions */
2289 return dir
->idEntries
[iIndex
].wResId
;
2292 /* Avoid paletted icons on non-paletted device */
2293 if (bppDesired
> 8 && BitCount
> 8)
2298 /* Now find the entry with the best depth */
2299 for(i
= 0; i
< dir
->idCount
; i
++)
2301 entry
= &dir
->idEntries
[i
];
2302 width
= fIcon
? entry
->ResInfo
.icon
.bWidth
: entry
->ResInfo
.cursor
.wWidth
;
2303 height
= fIcon
? entry
->ResInfo
.icon
.bHeight
: entry
->ResInfo
.cursor
.wHeight
/2;
2304 /* 0 represents 256 */
2305 if(!width
) width
= 256;
2306 if(!height
) height
= 256;
2307 /* Check if this is the best match we had */
2308 score
= 2*(abs(width
- cxDesired
) + abs(height
- cyDesired
));
2309 if(width
> cxDesired
)
2310 score
-= width
- cxDesired
;
2311 if(height
> cyDesired
)
2312 score
-= height
- cyDesired
;
2313 if(score
!= bestScore
)
2316 if(entry
->wBitCount
== bppDesired
)
2317 return entry
->wResId
;
2318 /* We take the highest possible but smaller than the display depth */
2319 if((entry
->wBitCount
> BitCount
) && (entry
->wBitCount
< bppDesired
))
2321 /* Avoid paletted icons on non paletted devices */
2322 if ((entry
->wBitCount
<= 8) && notPaletted
)
2325 BitCount
= entry
->wBitCount
;
2330 return dir
->idEntries
[iIndex
].wResId
;
2332 /* No inferior or equal depth available. Get the smallest bigger one */
2335 for(i
= 0; i
< dir
->idCount
; i
++)
2337 entry
= &dir
->idEntries
[i
];
2338 width
= fIcon
? entry
->ResInfo
.icon
.bWidth
: entry
->ResInfo
.cursor
.wWidth
;
2339 height
= fIcon
? entry
->ResInfo
.icon
.bHeight
: entry
->ResInfo
.cursor
.wHeight
/2;
2340 /* 0 represents 256 */
2341 if(!width
) width
= 256;
2342 if(!height
) height
= 256;
2343 /* Check if this is the best match we had */
2344 score
= 2*(abs(width
- cxDesired
) + abs(height
- cyDesired
));
2345 if(width
> cxDesired
)
2346 score
-= width
- cxDesired
;
2347 if(height
> cyDesired
)
2348 score
-= height
- cyDesired
;
2349 if(score
!= bestScore
)
2351 /* Check the bit depth */
2352 if(entry
->wBitCount
< BitCount
)
2354 if((entry
->wBitCount
<= 8) && notPaletted
)
2357 BitCount
= entry
->wBitCount
;
2361 return dir
->idEntries
[iIndex
].wResId
;
2366 HICON WINAPI
CreateIcon(
2367 _In_opt_ HINSTANCE hInstance
,
2371 _In_ BYTE cBitsPixel
,
2372 _In_
const BYTE
*lpbANDbits
,
2373 _In_
const BYTE
*lpbXORbits
2379 TRACE_(icon
)("%dx%d, planes %d, bpp %d, xor %p, and %p\n",
2380 nWidth
, nHeight
, cPlanes
, cBitsPixel
, lpbXORbits
, lpbANDbits
);
2383 iinfo
.xHotspot
= nWidth
/ 2;
2384 iinfo
.yHotspot
= nHeight
/ 2;
2385 if (cPlanes
* cBitsPixel
> 1)
2387 iinfo
.hbmColor
= CreateBitmap( nWidth
, nHeight
, cPlanes
, cBitsPixel
, lpbXORbits
);
2388 iinfo
.hbmMask
= CreateBitmap( nWidth
, nHeight
, 1, 1, lpbANDbits
);
2392 iinfo
.hbmMask
= CreateBitmap( nWidth
, nHeight
* 2, 1, 1, lpbANDbits
);
2393 iinfo
.hbmColor
= NULL
;
2396 hIcon
= CreateIconIndirect( &iinfo
);
2398 DeleteObject( iinfo
.hbmMask
);
2399 if (iinfo
.hbmColor
) DeleteObject( iinfo
.hbmColor
);
2404 HICON WINAPI
CreateIconFromResource(
2405 _In_ PBYTE presbits
,
2406 _In_ DWORD dwResSize
,
2411 return CreateIconFromResourceEx( presbits
, dwResSize
, fIcon
, dwVer
, 0, 0, LR_DEFAULTSIZE
| LR_SHARED
);
2414 HICON WINAPI
CreateIconFromResourceEx(
2415 _In_ PBYTE pbIconBits
,
2416 _In_ DWORD cbIconBits
,
2418 _In_ DWORD dwVersion
,
2424 CURSORDATA cursorData
;
2428 TRACE("%p, %lu, %lu, %lu, %i, %i, %lu.\n", pbIconBits
, cbIconBits
, fIcon
, dwVersion
, cxDesired
, cyDesired
, uFlags
);
2430 if(uFlags
& LR_DEFAULTSIZE
)
2432 if(!cxDesired
) cxDesired
= GetSystemMetrics(fIcon
? SM_CXICON
: SM_CXCURSOR
);
2433 if(!cyDesired
) cyDesired
= GetSystemMetrics(fIcon
? SM_CYICON
: SM_CYCURSOR
);
2436 ZeroMemory(&cursorData
, sizeof(cursorData
));
2437 cursorData
.cx
= cxDesired
;
2438 cursorData
.cy
= cyDesired
;
2439 cursorData
.rt
= (USHORT
)((ULONG_PTR
)(fIcon
? RT_ICON
: RT_CURSOR
));
2441 /* Convert to win32k-ready data */
2442 if(!memcmp(pbIconBits
, "RIFF", 4))
2444 if(!CURSORICON_GetCursorDataFromANI(&cursorData
, pbIconBits
, cbIconBits
, uFlags
))
2446 ERR("Could not get cursor data from .ani.\n");
2449 isAnimated
= !!(cursorData
.CURSORF_flags
& CURSORF_ACON
);
2453 /* It is possible to pass Icon Directories to this API */
2454 int wResId
= LookupIconIdFromDirectoryEx(pbIconBits
, fIcon
, cxDesired
, cyDesired
, uFlags
);
2455 HANDLE ResHandle
= NULL
;
2460 CURSORICONDIR
* pCurIconDir
= (CURSORICONDIR
*)pbIconBits
;
2462 TRACE("Pointer points to a directory structure.\n");
2464 /* So this is a pointer to an icon directory structure. Find the module */
2465 if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
| GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
,
2466 (LPCWSTR
)pbIconBits
,
2472 /* Check we were given the right type of resource */
2473 if((fIcon
&& pCurIconDir
->idType
== 2) || (!fIcon
&& pCurIconDir
->idType
== 1))
2475 WARN("Got a %s directory pointer, but called for a %s", fIcon
? "cursor" : "icon", fIcon
? "icon" : "cursor");
2479 /* Get the relevant resource pointer */
2480 hrsrc
= FindResourceW(
2482 MAKEINTRESOURCEW(wResId
),
2483 fIcon
? RT_ICON
: RT_CURSOR
);
2487 ResHandle
= LoadResource(hinst
, hrsrc
);
2491 pbIconBits
= LockResource(ResHandle
);
2494 FreeResource(ResHandle
);
2500 WORD
* pt
= (WORD
*)pbIconBits
;
2501 cursorData
.xHotspot
= *pt
++;
2502 cursorData
.yHotspot
= *pt
++;
2503 pbIconBits
= (PBYTE
)pt
;
2506 if (!CURSORICON_GetCursorDataFromBMI(&cursorData
, (BITMAPINFO
*)pbIconBits
))
2508 ERR("Couldn't fill the CURSORDATA structure.\n");
2510 FreeResource(ResHandle
);
2514 FreeResource(ResHandle
);
2518 if (uFlags
& LR_SHARED
)
2519 cursorData
.CURSORF_flags
|= CURSORF_LRSHARED
;
2521 hIcon
= NtUserxCreateEmptyCurObject(isAnimated
);
2525 if(!NtUserSetCursorIconData(hIcon
, NULL
, NULL
, &cursorData
))
2527 ERR("NtUserSetCursorIconData failed.\n");
2528 NtUserDestroyCursor(hIcon
, TRUE
);
2533 HeapFree(GetProcessHeap(), 0, cursorData
.aspcur
);
2540 HeapFree(GetProcessHeap(), 0, cursorData
.aspcur
);
2541 DeleteObject(cursorData
.hbmMask
);
2542 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
2543 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
2548 HICON WINAPI
CreateIconIndirect(
2549 _In_ PICONINFO piconinfo
2552 /* As simple as creating a handle, and let win32k deal with the bitmaps */
2554 CURSORDATA cursorData
;
2556 TRACE("%p.\n", piconinfo
);
2558 ZeroMemory(&cursorData
, sizeof(cursorData
));
2560 if(!CURSORICON_GetCursorDataFromIconInfo(&cursorData
, piconinfo
))
2563 hiconRet
= NtUserxCreateEmptyCurObject(FALSE
);
2567 if(!NtUserSetCursorIconData(hiconRet
, NULL
, NULL
, &cursorData
))
2569 NtUserDestroyCursor(hiconRet
, FALSE
);
2573 TRACE("Returning 0x%08x.\n", hiconRet
);
2579 DeleteObject(cursorData
.hbmMask
);
2580 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
2581 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
2586 HCURSOR WINAPI
CreateCursor(
2587 _In_opt_ HINSTANCE hInst
,
2592 _In_
const VOID
*pvANDPlane
,
2593 _In_
const VOID
*pvXORPlane
2599 TRACE_(cursor
)("%dx%d spot=%d,%d xor=%p and=%p\n",
2600 nWidth
, nHeight
, xHotSpot
, yHotSpot
, pvXORPlane
, pvANDPlane
);
2603 info
.xHotspot
= xHotSpot
;
2604 info
.yHotspot
= yHotSpot
;
2605 info
.hbmMask
= CreateBitmap( nWidth
, nHeight
, 1, 1, pvANDPlane
);
2606 info
.hbmColor
= CreateBitmap( nWidth
, nHeight
, 1, 1, pvXORPlane
);
2607 hCursor
= CreateIconIndirect( &info
);
2608 DeleteObject( info
.hbmMask
);
2609 DeleteObject( info
.hbmColor
);
2613 BOOL WINAPI
SetSystemCursor(
2620 hcur
= LoadImageW( 0, MAKEINTRESOURCE(id
), IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
);
2626 return NtUserSetSystemCursor(hcur
,id
);
2629 BOOL WINAPI
SetCursorPos(
2634 return NtUserxSetCursorPos(X
,Y
);
2637 BOOL WINAPI
GetCursorPos(
2638 _Out_ LPPOINT lpPoint
2641 return NtUserxGetCursorPos(lpPoint
);
2644 int WINAPI
ShowCursor(
2648 return NtUserxShowCursor(bShow
);
2651 HCURSOR WINAPI
GetCursor(void)
2653 return (HCURSOR
)NtUserGetThreadState(THREADSTATE_GETCURSOR
);
2656 BOOL WINAPI
DestroyCursor(
2657 _In_ HCURSOR hCursor
2660 return NtUserDestroyCursor(hCursor
, FALSE
);
2665 GetCursorFrameInfo(HCURSOR hCursor
, DWORD reserved
, DWORD istep
, PINT rate_jiffies
, DWORD
*num_steps
)
2667 return NtUserGetCursorFrameInfo(hCursor
, istep
, rate_jiffies
, num_steps
);