2 * PROJECT: ReactOS user32.dll
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/user32/windows/cursoricon.c
5 * PURPOSE: cursor and icons implementation
6 * PROGRAMMER: Jérôme Gardou (jerome.gardou@reactos.org)
11 #include <wine/debug.h>
13 WINE_DEFAULT_DEBUG_CHANNEL(cursor
);
14 WINE_DECLARE_DEBUG_CHANNEL(icon
);
15 //WINE_DECLARE_DEBUG_CHANNEL(resource);
17 /* We only use Wide string functions */
18 #undef MAKEINTRESOURCE
19 #define MAKEINTRESOURCE MAKEINTRESOURCEW
21 /************* USER32 INTERNAL FUNCTIONS **********/
23 /* This callback routine is called directly after switching to gui mode */
26 User32SetupDefaultCursors(PVOID Arguments
,
29 BOOL
*DefaultCursor
= (BOOL
*)Arguments
;
34 /* set default cursor */
35 hCursor
= LoadCursorW(0, IDC_ARROW
);
40 /* FIXME load system cursor scheme */
42 hCursor
= LoadCursorW(0, IDC_ARROW
);
46 return(ZwCallbackReturn(&hCursor
, sizeof(HCURSOR
), STATUS_SUCCESS
));
49 BOOL
get_icon_size(HICON hIcon
, SIZE
*size
)
51 return NtUserGetIconSize(hIcon
, 0, &size
->cx
, &size
->cy
);
54 HCURSOR
CursorIconToCursor(HICON hIcon
, BOOL SemiTransparent
)
60 /************* IMPLEMENTATION HELPERS ******************/
62 static const WCHAR DISPLAYW
[] = L
"DISPLAY";
64 static void *map_fileW( LPCWSTR name
, LPDWORD filesize
)
66 HANDLE hFile
, hMapping
;
69 hFile
= CreateFileW( name
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
70 OPEN_EXISTING
, FILE_FLAG_RANDOM_ACCESS
, 0 );
71 if (hFile
!= INVALID_HANDLE_VALUE
)
73 hMapping
= CreateFileMappingW( hFile
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
76 ptr
= MapViewOfFile( hMapping
, FILE_MAP_READ
, 0, 0, 0 );
77 CloseHandle( hMapping
);
79 *filesize
= GetFileSize( hFile
, NULL
);
86 static int get_dib_image_size( int width
, int height
, int depth
)
88 return (((width
* depth
+ 31) / 8) & ~3) * abs( height
);
91 static BOOL
is_dib_monochrome( const BITMAPINFO
* info
)
93 if (info
->bmiHeader
.biBitCount
!= 1) return FALSE
;
95 if (info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
97 const RGBTRIPLE
*rgb
= ((const BITMAPCOREINFO
*)info
)->bmciColors
;
99 /* Check if the first color is black */
100 if ((rgb
->rgbtRed
== 0) && (rgb
->rgbtGreen
== 0) && (rgb
->rgbtBlue
== 0))
104 /* Check if the second color is white */
105 return ((rgb
->rgbtRed
== 0xff) && (rgb
->rgbtGreen
== 0xff)
106 && (rgb
->rgbtBlue
== 0xff));
110 else /* assume BITMAPINFOHEADER */
112 const RGBQUAD
*rgb
= info
->bmiColors
;
114 /* Check if the first color is black */
115 if ((rgb
->rgbRed
== 0) && (rgb
->rgbGreen
== 0) &&
116 (rgb
->rgbBlue
== 0) && (rgb
->rgbReserved
== 0))
120 /* Check if the second color is white */
121 return ((rgb
->rgbRed
== 0xff) && (rgb
->rgbGreen
== 0xff)
122 && (rgb
->rgbBlue
== 0xff) && (rgb
->rgbReserved
== 0));
128 static int bitmap_info_size( const BITMAPINFO
* info
, WORD coloruse
)
130 unsigned int colors
, size
, masks
= 0;
132 if (info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
134 const BITMAPCOREHEADER
*core
= (const BITMAPCOREHEADER
*)info
;
135 colors
= (core
->bcBitCount
<= 8) ? 1 << core
->bcBitCount
: 0;
136 return sizeof(BITMAPCOREHEADER
) + colors
*
137 ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBTRIPLE
) : sizeof(WORD
));
139 else /* assume BITMAPINFOHEADER */
141 colors
= info
->bmiHeader
.biClrUsed
;
142 if (colors
> 256) /* buffer overflow otherwise */
144 if (!colors
&& (info
->bmiHeader
.biBitCount
<= 8))
145 colors
= 1 << info
->bmiHeader
.biBitCount
;
146 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
) masks
= 3;
147 size
= max( info
->bmiHeader
.biSize
, sizeof(BITMAPINFOHEADER
) + masks
* sizeof(DWORD
) );
148 return size
+ colors
* ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBQUAD
) : sizeof(WORD
));
152 static int DIB_GetBitmapInfo( const BITMAPINFOHEADER
*header
, LONG
*width
,
153 LONG
*height
, WORD
*bpp
, DWORD
*compr
)
155 if (header
->biSize
== sizeof(BITMAPCOREHEADER
))
157 const BITMAPCOREHEADER
*core
= (const BITMAPCOREHEADER
*)header
;
158 *width
= core
->bcWidth
;
159 *height
= core
->bcHeight
;
160 *bpp
= core
->bcBitCount
;
164 else if (header
->biSize
== sizeof(BITMAPINFOHEADER
) ||
165 header
->biSize
== sizeof(BITMAPV4HEADER
) ||
166 header
->biSize
== sizeof(BITMAPV5HEADER
))
168 *width
= header
->biWidth
;
169 *height
= header
->biHeight
;
170 *bpp
= header
->biBitCount
;
171 *compr
= header
->biCompression
;
174 ERR("(%d): unknown/wrong size for header\n", header
->biSize
);
178 /* copy an icon bitmap, even when it can't be selected into a DC */
179 /* helper for CreateIconIndirect */
180 static void stretch_blt_icon(HDC hdc_dst
, int dst_width
, int dst_height
, HBITMAP src
)
182 HDC hdc
= CreateCompatibleDC( 0 );
186 GetObjectW(src
, sizeof(bm
), &bm
);
188 hbmpPrev
= SelectObject(hdc
, src
);
190 if (!hbmpPrev
) /* do it the hard way */
195 if (!(info
= HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )))) return;
196 info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
197 info
->bmiHeader
.biWidth
= bm
.bmWidth
;
198 info
->bmiHeader
.biHeight
= bm
.bmHeight
;
199 info
->bmiHeader
.biPlanes
= GetDeviceCaps( hdc_dst
, PLANES
);
200 info
->bmiHeader
.biBitCount
= GetDeviceCaps( hdc_dst
, BITSPIXEL
);
201 info
->bmiHeader
.biCompression
= BI_RGB
;
202 info
->bmiHeader
.biSizeImage
= get_dib_image_size( bm
.bmWidth
, bm
.bmHeight
, info
->bmiHeader
.biBitCount
);
203 info
->bmiHeader
.biXPelsPerMeter
= 0;
204 info
->bmiHeader
.biYPelsPerMeter
= 0;
205 info
->bmiHeader
.biClrUsed
= 0;
206 info
->bmiHeader
.biClrImportant
= 0;
207 bits
= HeapAlloc( GetProcessHeap(), 0, info
->bmiHeader
.biSizeImage
);
208 if (bits
&& GetDIBits( hdc
, src
, 0, bm
.bmHeight
, bits
, info
, DIB_RGB_COLORS
))
209 StretchDIBits( hdc_dst
, 0, 0, dst_width
, dst_height
,
210 0, 0, bm
.bmWidth
, bm
.bmHeight
, bits
, info
, DIB_RGB_COLORS
, SRCCOPY
);
212 HeapFree( GetProcessHeap(), 0, bits
);
213 HeapFree( GetProcessHeap(), 0, info
);
217 StretchBlt( hdc_dst
, 0, 0, dst_width
, dst_height
, hdc
, 0, 0, bm
.bmWidth
, bm
.bmHeight
, SRCCOPY
);
218 SelectObject(hdc
, hbmpPrev
);
224 /***********************************************************************
227 static BOOL
bmi_has_alpha( const BITMAPINFO
*info
, const void *bits
)
230 BOOL has_alpha
= FALSE
;
231 const unsigned char *ptr
= bits
;
233 if (info
->bmiHeader
.biBitCount
!= 32) return FALSE
;
234 for (i
= 0; i
< info
->bmiHeader
.biWidth
* abs(info
->bmiHeader
.biHeight
); i
++, ptr
+= 4)
235 if ((has_alpha
= (ptr
[3] != 0))) break;
239 /***********************************************************************
240 * create_alpha_bitmap
242 * Create the alpha bitmap for a 32-bpp icon that has an alpha channel.
247 _In_opt_ HBITMAP color
,
248 _In_opt_ BITMAPINFO
*src_info
,
249 _In_opt_
const void *color_bits
,
253 HBITMAP alpha
= NULL
, hbmpOld
;
254 HDC hdc
= NULL
, hdcScreen
;
259 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
262 hdc
= CreateCompatibleDC(hdcScreen
);
272 BITMAPINFO
*info
= NULL
;
274 TRACE("Creating alpha bitmap from existing bitmap.\n");
276 if (!GetObjectW( color
, sizeof(bm
), &bm
))
278 if (bm
.bmBitsPixel
!= 32)
281 size
= get_dib_image_size(bm
.bmWidth
, bm
.bmHeight
, 32);
283 info
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(BITMAPINFO
, bmiColors
[256]));
286 info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
287 info
->bmiHeader
.biWidth
= bm
.bmWidth
;
288 info
->bmiHeader
.biHeight
= -bm
.bmHeight
;
289 info
->bmiHeader
.biPlanes
= 1;
290 info
->bmiHeader
.biBitCount
= 32;
291 info
->bmiHeader
.biCompression
= BI_RGB
;
292 info
->bmiHeader
.biSizeImage
= size
;
293 info
->bmiHeader
.biXPelsPerMeter
= 0;
294 info
->bmiHeader
.biYPelsPerMeter
= 0;
295 info
->bmiHeader
.biClrUsed
= 0;
296 info
->bmiHeader
.biClrImportant
= 0;
298 bits
= HeapAlloc(GetProcessHeap(), 0, size
);
301 HeapFree(GetProcessHeap(), 0, info
);
304 if(!GetDIBits( hdc
, color
, 0, bm
.bmHeight
, bits
, info
, DIB_RGB_COLORS
))
306 HeapFree(GetProcessHeap(), 0, info
);
309 if (!bmi_has_alpha( info
, bits
))
311 HeapFree(GetProcessHeap(), 0, info
);
315 /* pre-multiply by alpha */
316 for (ptr
= bits
; ptr
< ((BYTE
*)bits
+ size
); ptr
+= 4)
318 unsigned int alpha
= ptr
[3];
319 ptr
[0] = (ptr
[0] * alpha
) / 255;
320 ptr
[1] = (ptr
[1] * alpha
) / 255;
321 ptr
[2] = (ptr
[2] * alpha
) / 255;
324 /* Directly create a 32-bits DDB (thanks to undocumented CreateDIBitmap flag). */
325 alpha
= CreateDIBitmap(hdc
, NULL
, CBM_INIT
| 2, bits
, info
, DIB_RGB_COLORS
);
327 HeapFree(GetProcessHeap(), 0, info
);
333 LONG orig_width
, orig_height
;
335 TRACE("Creating alpha bitmap from bitmap info.\n");
337 if(!bmi_has_alpha(src_info
, color_bits
))
340 if(!DIB_GetBitmapInfo(&src_info
->bmiHeader
, &orig_width
, &orig_height
, &bpp
, &compr
))
345 size
= get_dib_image_size(orig_width
, orig_height
, bpp
);
346 bits
= HeapAlloc(GetProcessHeap(), 0, size
);
349 CopyMemory(bits
, color_bits
, size
);
350 /* pre-multiply by alpha */
351 for (ptr
= bits
; ptr
< ((BYTE
*)bits
+ size
); ptr
+= 4)
353 unsigned int alpha
= ptr
[3];
354 ptr
[0] = (ptr
[0] * alpha
) / 255;
355 ptr
[1] = (ptr
[1] * alpha
) / 255;
356 ptr
[2] = (ptr
[2] * alpha
) / 255;
359 /* Create the bitmap. Set the bitmap info to have the right width and height */
360 if(src_info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
362 ((BITMAPCOREHEADER
*)&src_info
->bmiHeader
)->bcWidth
= width
;
363 ((BITMAPCOREHEADER
*)&src_info
->bmiHeader
)->bcHeight
= height
;
367 src_info
->bmiHeader
.biWidth
= width
;
368 src_info
->bmiHeader
.biHeight
= height
;
370 /* Directly create a 32-bits DDB (thanks to undocumented CreateDIBitmap flag). */
371 alpha
= CreateDIBitmap(hdcScreen
, NULL
, 2, NULL
, src_info
, DIB_RGB_COLORS
);
373 if(src_info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
375 ((BITMAPCOREHEADER
*)&src_info
->bmiHeader
)->bcWidth
= orig_width
;
376 ((BITMAPCOREHEADER
*)&src_info
->bmiHeader
)->bcHeight
= orig_height
;
380 src_info
->bmiHeader
.biWidth
= orig_width
;
381 src_info
->bmiHeader
.biHeight
= orig_height
;
385 hbmpOld
= SelectObject(hdc
, alpha
);
392 if(!StretchDIBits( hdc
, 0, 0, width
, height
,
393 0, 0, orig_width
, orig_height
,
394 bits
, src_info
, DIB_RGB_COLORS
, SRCCOPY
))
396 SelectObject(hdc
, hbmpOld
);
403 SelectObject(hdc
, hbmpOld
);
410 if(bits
) HeapFree(GetProcessHeap(), 0, bits
);
412 TRACE("Returning 0x%08x.\n", alpha
);
416 #include "pshpack1.h"
427 } CURSORICONFILEDIRENTRY
;
434 CURSORICONFILEDIRENTRY idEntries
[1];
439 const CURSORICONFILEDIRENTRY
*
440 get_best_icon_file_entry(
441 _In_
const CURSORICONFILEDIR
* dir
,
442 _In_ DWORD dwFileSize
,
449 CURSORICONDIR
* fakeDir
;
450 CURSORICONDIRENTRY
* fakeEntry
;
452 const CURSORICONFILEDIRENTRY
* entry
;
454 /* Check our file is what it claims to be */
455 if ( dwFileSize
< sizeof(*dir
) )
458 if (dwFileSize
< FIELD_OFFSET(CURSORICONFILEDIR
, idEntries
[dir
->idCount
]))
463 * We allocate a buffer, fake it as if it was a pointer to a resource in a module,
464 * pass it to LookupIconIdFromDirectoryEx and get back the index we have to use
466 fakeDir
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(CURSORICONDIR
, idEntries
[dir
->idCount
]));
469 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
472 fakeDir
->idReserved
= 0;
473 fakeDir
->idType
= dir
->idType
;
474 fakeDir
->idCount
= dir
->idCount
;
475 for(i
= 0; i
<dir
->idCount
; i
++)
477 fakeEntry
= &fakeDir
->idEntries
[i
];
478 entry
= &dir
->idEntries
[i
];
479 /* Take this as an occasion to perform a size check */
480 if ((entry
->dwDIBOffset
> dwFileSize
)
481 || ((entry
->dwDIBOffset
+ entry
->dwDIBSize
) > dwFileSize
))
483 ERR("Corrupted icon file?.\n");
484 HeapFree(GetProcessHeap(), 0, fakeDir
);
487 /* File icon/cursors are not like resource ones */
490 fakeEntry
->ResInfo
.icon
.bWidth
= entry
->bWidth
;
491 fakeEntry
->ResInfo
.icon
.bHeight
= entry
->bHeight
;
492 fakeEntry
->ResInfo
.icon
.bColorCount
= 0;
493 fakeEntry
->ResInfo
.icon
.bReserved
= 0;
497 fakeEntry
->ResInfo
.cursor
.wWidth
= entry
->bWidth
;
498 fakeEntry
->ResInfo
.cursor
.wHeight
= entry
->bHeight
;
500 /* Let's assume there's always one plane */
501 fakeEntry
->wPlanes
= 1;
502 /* We must get the bitcount from the BITMAPINFOHEADER itself */
503 if (((BITMAPINFOHEADER
*)((char *)dir
+ entry
->dwDIBOffset
))->biSize
== sizeof(BITMAPCOREHEADER
))
504 fakeEntry
->wBitCount
= ((BITMAPCOREHEADER
*)((char *)dir
+ entry
->dwDIBOffset
))->bcBitCount
;
506 fakeEntry
->wBitCount
= ((BITMAPINFOHEADER
*)((char *)dir
+ entry
->dwDIBOffset
))->biBitCount
;
507 fakeEntry
->dwBytesInRes
= entry
->dwDIBSize
;
508 fakeEntry
->wResId
= i
+ 1;
511 /* Now call LookupIconIdFromResourceEx */
512 i
= LookupIconIdFromDirectoryEx((PBYTE
)fakeDir
, bIcon
, cxDesired
, cyDesired
, fuLoad
& LR_MONOCHROME
);
513 /* We don't need this anymore */
514 HeapFree(GetProcessHeap(), 0, fakeDir
);
517 WARN("Unable to get a fit entry index.\n");
522 return &dir
->idEntries
[i
-1];
526 get_best_icon_file_offset(
527 _In_
const LPBYTE dir
,
528 _In_ DWORD dwFileSize
,
533 _Out_ POINT
*ptHotSpot
536 const CURSORICONFILEDIRENTRY
*entry
;
538 entry
= get_best_icon_file_entry((CURSORICONFILEDIR
*) dir
, dwFileSize
, cxDesired
, cyDesired
, bIcon
, fuLoad
);
542 ptHotSpot
->x
= entry
->xHotspot
;
543 ptHotSpot
->y
= entry
->yHotspot
;
547 return entry
->dwDIBOffset
;
554 /************* IMPLEMENTATION CORE ****************/
556 static BOOL
CURSORICON_GetCursorDataFromBMI(
557 _Inout_ CURSORDATA
* pdata
,
558 _In_
const BITMAPINFO
*pbmi
561 UINT ubmiSize
= bitmap_info_size(pbmi
, DIB_RGB_COLORS
);
562 BOOL monochrome
= is_dib_monochrome(pbmi
);
568 BITMAPINFO
* pbmiCopy
;
569 HBITMAP hbmpOld
= NULL
;
570 BOOL bResult
= FALSE
;
571 const VOID
*pvColor
, *pvMask
;
573 ibmpType
= DIB_GetBitmapInfo(&pbmi
->bmiHeader
, &width
, &height
, &bpp
, &compr
);
578 /* No compression for icons */
582 /* If no dimensions were set, use the one from the icon */
583 if(!pdata
->cx
) pdata
->cx
= width
;
584 if(!pdata
->cy
) pdata
->cy
= height
< 0 ? -height
/2 : height
/2;
586 /* Fix the hotspot coords */
587 if(pdata
->rt
== (USHORT
)((ULONG_PTR
)RT_CURSOR
))
589 if(pdata
->cx
!= width
)
590 pdata
->xHotspot
= (pdata
->xHotspot
* pdata
->cx
) / width
;
591 if(pdata
->cy
!= height
/2)
592 pdata
->yHotspot
= (pdata
->yHotspot
* pdata
->cy
* 2) / height
;
596 pdata
->xHotspot
= pdata
->cx
/2;
597 pdata
->yHotspot
= pdata
->cy
/2;
600 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
603 hdc
= CreateCompatibleDC(hdcScreen
);
610 pbmiCopy
= HeapAlloc(GetProcessHeap(), 0, max(ubmiSize
, FIELD_OFFSET(BITMAPINFO
, bmiColors
[3])));
613 RtlCopyMemory(pbmiCopy
, pbmi
, ubmiSize
);
615 /* In an icon/cursor, the BITMAPINFO holds twice the height */
616 if(pbmiCopy
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
617 ((BITMAPCOREHEADER
*)&pbmiCopy
->bmiHeader
)->bcHeight
/= 2;
619 pbmiCopy
->bmiHeader
.biHeight
/= 2;
622 pvColor
= (const char*)pbmi
+ ubmiSize
;
623 pvMask
= (const char*)pvColor
+
624 get_dib_image_size(width
, height
, bpp
);
629 /* Create the 1bpp bitmap which will contain everything */
630 pdata
->hbmColor
= NULL
;
631 pdata
->hbmMask
= CreateBitmap(pdata
->cx
, pdata
->cy
* 2, 1, 1, NULL
);
634 hbmpOld
= SelectObject(hdc
, pdata
->hbmMask
);
638 if(!StretchDIBits(hdc
, 0, pdata
->cy
, pdata
->cx
, pdata
->cy
,
640 pvColor
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
))
646 /* Create the bitmap. It has to be compatible with the screen surface */
647 pdata
->hbmColor
= CreateCompatibleBitmap(hdcScreen
, pdata
->cx
, pdata
->cy
);
650 /* Create the 1bpp mask bitmap */
651 pdata
->hbmMask
= CreateBitmap(pdata
->cx
, pdata
->cy
, 1, 1, NULL
);
654 hbmpOld
= SelectObject(hdc
, pdata
->hbmColor
);
657 if(!StretchDIBits(hdc
, 0, 0, pdata
->cx
, pdata
->cy
,
659 pvColor
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
))
661 pdata
->bpp
= GetDeviceCaps(hdcScreen
, BITSPIXEL
);
662 pdata
->hbmAlpha
= create_alpha_bitmap(NULL
, pbmiCopy
, pvColor
, pdata
->cx
, pdata
->cy
);
664 /* Now convert the info to monochrome for the mask bits */
665 if (pbmiCopy
->bmiHeader
.biSize
!= sizeof(BITMAPCOREHEADER
))
667 RGBQUAD
*rgb
= pbmiCopy
->bmiColors
;
669 pbmiCopy
->bmiHeader
.biClrUsed
= pbmiCopy
->bmiHeader
.biClrImportant
= 2;
670 rgb
[0].rgbBlue
= rgb
[0].rgbGreen
= rgb
[0].rgbRed
= 0x00;
671 rgb
[1].rgbBlue
= rgb
[1].rgbGreen
= rgb
[1].rgbRed
= 0xff;
672 rgb
[0].rgbReserved
= rgb
[1].rgbReserved
= 0;
673 pbmiCopy
->bmiHeader
.biBitCount
= 1;
677 RGBTRIPLE
*rgb
= (RGBTRIPLE
*)(((BITMAPCOREHEADER
*)pbmiCopy
) + 1);
679 rgb
[0].rgbtBlue
= rgb
[0].rgbtGreen
= rgb
[0].rgbtRed
= 0x00;
680 rgb
[1].rgbtBlue
= rgb
[1].rgbtGreen
= rgb
[1].rgbtRed
= 0xff;
681 ((BITMAPCOREHEADER
*)&pbmiCopy
->bmiHeader
)->bcBitCount
= 1;
684 /* Set the mask bits */
685 if(!SelectObject(hdc
, pdata
->hbmMask
))
687 bResult
= StretchDIBits(hdc
, 0, 0, pdata
->cx
, pdata
->cy
,
689 pvMask
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
) != 0;
693 if(hbmpOld
) SelectObject(hdc
, hbmpOld
);
695 if(pbmiCopy
) HeapFree(GetProcessHeap(), 0, pbmiCopy
);
696 /* Clean up in case of failure */
699 if(pdata
->hbmMask
) DeleteObject(pdata
->hbmMask
);
700 if(pdata
->hbmColor
) DeleteObject(pdata
->hbmColor
);
701 if(pdata
->hbmAlpha
) DeleteObject(pdata
->hbmAlpha
);
706 static BOOL
CURSORICON_GetCursorDataFromIconInfo(
707 _Out_ CURSORDATA
* pCursorData
,
708 _In_ ICONINFO
* pIconInfo
713 ZeroMemory(pCursorData
, sizeof(*pCursorData
));
714 if(pIconInfo
->hbmColor
)
716 /* We must convert the color bitmap to screen format */
717 HDC hdcScreen
, hdcMem
;
720 /* The mask dictates its dimensions */
721 if (!GetObject(pIconInfo
->hbmMask
, sizeof(bm
), &bm
))
723 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
726 hdcMem
= CreateCompatibleDC(hdcScreen
);
732 pCursorData
->hbmColor
= CreateCompatibleBitmap(hdcScreen
, bm
.bmWidth
, bm
.bmHeight
);
734 if (!pCursorData
->hbmColor
)
739 hbmpPrev
= SelectObject(hdcMem
, pCursorData
->hbmColor
);
743 DeleteObject(pCursorData
->hbmColor
);
746 stretch_blt_icon( hdcMem
, bm
.bmWidth
, bm
.bmHeight
, pIconInfo
->hbmColor
);
747 SelectObject(hdcMem
, hbmpPrev
);
750 pCursorData
->hbmMask
= CopyImage(pIconInfo
->hbmMask
, IMAGE_BITMAP
, 0, 0, LR_MONOCHROME
);
751 if(!pCursorData
->hbmMask
)
754 /* Now, fill some information */
755 pCursorData
->rt
= (USHORT
)((ULONG_PTR
)(pIconInfo
->fIcon
? RT_ICON
: RT_CURSOR
));
756 if(pCursorData
->hbmColor
)
758 GetObject(pCursorData
->hbmColor
, sizeof(bm
), &bm
);
759 pCursorData
->bpp
= bm
.bmBitsPixel
;
760 pCursorData
->cx
= bm
.bmWidth
;
761 pCursorData
->cy
= bm
.bmHeight
;
762 if(pCursorData
->bpp
== 32)
763 pCursorData
->hbmAlpha
= create_alpha_bitmap(pCursorData
->hbmColor
, NULL
, NULL
, 0, 0);
767 GetObject(pCursorData
->hbmMask
, sizeof(bm
), &bm
);
768 pCursorData
->bpp
= 1;
769 pCursorData
->cx
= bm
.bmWidth
;
770 pCursorData
->cy
= bm
.bmHeight
/2;
775 pCursorData
->xHotspot
= pCursorData
->cx
/2;
776 pCursorData
->yHotspot
= pCursorData
->cy
/2;
780 pCursorData
->xHotspot
= pIconInfo
->xHotspot
;
781 pCursorData
->yHotspot
= pIconInfo
->yHotspot
;
788 #define RIFF_FOURCC( c0, c1, c2, c3 ) \
789 ( (DWORD)(BYTE)(c0) | ( (DWORD)(BYTE)(c1) << 8 ) | \
790 ( (DWORD)(BYTE)(c2) << 16 ) | ( (DWORD)(BYTE)(c3) << 24 ) )
792 #define ANI_RIFF_ID RIFF_FOURCC('R', 'I', 'F', 'F')
793 #define ANI_LIST_ID RIFF_FOURCC('L', 'I', 'S', 'T')
794 #define ANI_ACON_ID RIFF_FOURCC('A', 'C', 'O', 'N')
795 #define ANI_anih_ID RIFF_FOURCC('a', 'n', 'i', 'h')
796 #define ANI_seq__ID RIFF_FOURCC('s', 'e', 'q', ' ')
797 #define ANI_fram_ID RIFF_FOURCC('f', 'r', 'a', 'm')
798 #define ANI_rate_ID RIFF_FOURCC('r', 'a', 't', 'e')
800 #define ANI_FLAG_ICON 0x1
801 #define ANI_FLAG_SEQUENCE 0x2
803 #include <pshpack1.h>
818 const unsigned char *data
;
822 static void dump_ani_header( const ani_header
*header
)
824 TRACE(" header size: %d\n", header
->header_size
);
825 TRACE(" frames: %d\n", header
->num_frames
);
826 TRACE(" steps: %d\n", header
->num_steps
);
827 TRACE(" width: %d\n", header
->width
);
828 TRACE(" height: %d\n", header
->height
);
829 TRACE(" bpp: %d\n", header
->bpp
);
830 TRACE(" planes: %d\n", header
->num_planes
);
831 TRACE(" display rate: %d\n", header
->display_rate
);
832 TRACE(" flags: 0x%08x\n", header
->flags
);
835 /* Find an animated cursor chunk, given its type and ID */
836 static void riff_find_chunk( DWORD chunk_id
, DWORD chunk_type
, const riff_chunk_t
*parent_chunk
, riff_chunk_t
*chunk
)
838 const unsigned char *ptr
= parent_chunk
->data
;
839 const unsigned char *end
= parent_chunk
->data
+ (parent_chunk
->data_size
- (2 * sizeof(DWORD
)));
841 if (chunk_type
== ANI_LIST_ID
|| chunk_type
== ANI_RIFF_ID
) end
-= sizeof(DWORD
);
845 if ((!chunk_type
&& *(const DWORD
*)ptr
== chunk_id
)
846 || (chunk_type
&& *(const DWORD
*)ptr
== chunk_type
&& *((const DWORD
*)ptr
+ 2) == chunk_id
))
848 ptr
+= sizeof(DWORD
);
849 chunk
->data_size
= (*(const DWORD
*)ptr
+ 1) & ~1;
850 ptr
+= sizeof(DWORD
);
851 if (chunk_type
== ANI_LIST_ID
|| chunk_type
== ANI_RIFF_ID
) ptr
+= sizeof(DWORD
);
857 ptr
+= sizeof(DWORD
);
858 ptr
+= (*(const DWORD
*)ptr
+ 1) & ~1;
859 ptr
+= sizeof(DWORD
);
863 static BOOL
CURSORICON_GetCursorDataFromANI(
864 _Inout_ CURSORDATA
* pCurData
,
865 _In_
const BYTE
*pData
,
866 _In_ DWORD dwDataSize
,
871 const ani_header
*pHeader
;
872 riff_chunk_t root_chunk
= { dwDataSize
, pData
};
873 riff_chunk_t ACON_chunk
= {0};
874 riff_chunk_t anih_chunk
= {0};
875 riff_chunk_t fram_chunk
= {0};
876 riff_chunk_t rate_chunk
= {0};
877 riff_chunk_t seq_chunk
= {0};
878 const unsigned char *icon_chunk
;
879 const unsigned char *icon_data
;
881 /* Find the root chunk */
882 riff_find_chunk( ANI_ACON_ID
, ANI_RIFF_ID
, &root_chunk
, &ACON_chunk
);
883 if (!ACON_chunk
.data
)
885 ERR("Failed to get root chunk.\n");
889 /* Find the header chunk */
890 riff_find_chunk( ANI_anih_ID
, 0, &ACON_chunk
, &anih_chunk
);
891 if (!ACON_chunk
.data
)
893 ERR("Failed to get header chunk.\n");
896 pHeader
= (ani_header
*)anih_chunk
.data
;
897 dump_ani_header(pHeader
);
899 /* Set up the master data */
900 pCurData
->CURSORF_flags
|= CURSORF_ACON
;
901 pCurData
->cpcur
= pHeader
->num_frames
;
902 pCurData
->cicur
= pHeader
->num_steps
;
903 pCurData
->iicur
= pHeader
->display_rate
;
905 /* Get the sequences */
906 if (pHeader
->flags
& ANI_FLAG_SEQUENCE
)
908 riff_find_chunk( ANI_seq__ID
, 0, &ACON_chunk
, &seq_chunk
);
911 ERR("No sequence data although the flag is set!\n");
916 /* Get the frame rates */
917 riff_find_chunk( ANI_rate_ID
, 0, &ACON_chunk
, &rate_chunk
);
919 pCurData
->ajifRate
= (INT
*)rate_chunk
.data
;
921 /* Get the frames chunk */
922 riff_find_chunk( ANI_fram_ID
, ANI_LIST_ID
, &ACON_chunk
, &fram_chunk
);
923 if (!fram_chunk
.data
)
925 ERR("Failed to get icon list.\n");
928 icon_chunk
= fram_chunk
.data
;
929 icon_data
= fram_chunk
.data
+ (2 * sizeof(DWORD
));
931 if(pHeader
->num_frames
> 1)
933 /* Allocate frame descriptors, step indices and rates */
934 pCurData
->aspcur
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
935 pHeader
->num_frames
* sizeof(CURSORDATA
) + pHeader
->num_steps
* (sizeof(DWORD
) + sizeof(INT
)));
936 if(!pCurData
->aspcur
)
938 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
941 pCurData
->aicur
= (DWORD
*)(pCurData
->aspcur
+ pHeader
->num_frames
);
942 pCurData
->ajifRate
= (INT
*)(pCurData
->aicur
+ pHeader
->num_steps
);
945 for(i
=0; i
< pHeader
->num_frames
; i
++)
947 CURSORDATA
* pFrameData
;
948 const DWORD chunk_size
= *(const DWORD
*)(icon_chunk
+ sizeof(DWORD
));
949 const BITMAPINFO
* pbmi
;
951 if(pHeader
->num_frames
> 1)
952 pFrameData
= &pCurData
->aspcur
[i
];
954 pFrameData
= pCurData
;
956 pFrameData
->rt
= pCurData
->rt
;
958 if (pHeader
->flags
& ANI_FLAG_ICON
)
960 /* The chunks describe an icon file */
961 const CURSORICONFILEDIRENTRY
* pDirEntry
= get_best_icon_file_entry(
962 (const CURSORICONFILEDIR
*) icon_data
,
970 ERR("Unable to find the right file entry for frame %d.\n", i
);
973 pFrameData
->xHotspot
= pDirEntry
->xHotspot
;
974 pFrameData
->yHotspot
= pDirEntry
->yHotspot
;
975 if(!pHeader
->width
|| !pHeader
->height
)
977 pFrameData
->cx
= pDirEntry
->bWidth
;
978 pFrameData
->cy
= pDirEntry
->bHeight
;
982 pFrameData
->cx
= pHeader
->width
;
983 pFrameData
->cy
= pHeader
->height
;
985 pbmi
= (const BITMAPINFO
*) (icon_data
+ pDirEntry
->dwDIBOffset
);
989 /* The chunks just describe bitmaps */
990 pbmi
= (const BITMAPINFO
*)icon_data
;
991 pFrameData
->xHotspot
= pFrameData
->yHotspot
= 0;
994 /* Do the real work */
995 CURSORICON_GetCursorDataFromBMI(pFrameData
, pbmi
);
997 if(pHeader
->num_frames
> 1)
998 pFrameData
->CURSORF_flags
|= CURSORF_ACONFRAME
;
1000 pFrameData
->CURSORF_flags
&= ~CURSORF_ACON
;
1004 icon_chunk
+= chunk_size
+ (2 * sizeof(DWORD
));
1005 icon_data
= icon_chunk
+ (2 * sizeof(DWORD
));
1008 if(pHeader
->num_frames
<= 1)
1012 CopyMemory(pCurData
->ajifRate
, rate_chunk
.data
, pHeader
->num_steps
* sizeof(INT
));
1015 for(i
=0; i
< pHeader
->num_steps
; i
++)
1016 pCurData
->ajifRate
[i
] = pHeader
->display_rate
;
1019 if (pHeader
->flags
& ANI_FLAG_SEQUENCE
)
1021 CopyMemory(pCurData
->aicur
, seq_chunk
.data
, pHeader
->num_steps
* sizeof(DWORD
));
1025 for(i
=0; i
< pHeader
->num_steps
; i
++)
1026 pCurData
->aicur
[i
] = i
;
1032 HeapFree(GetProcessHeap(), 0, pCurData
->aspcur
);
1033 ZeroMemory(pCurData
, sizeof(CURSORDATA
));
1041 _In_opt_ HINSTANCE hinst
,
1042 _In_ LPCWSTR lpszName
,
1048 const BITMAPINFO
* pbmi
;
1049 BITMAPINFO
* pbmiScaled
= NULL
;
1050 BITMAPINFO
* pbmiCopy
= NULL
;
1051 const VOID
* pvMapping
= NULL
;
1053 HGLOBAL hgRsrc
= NULL
;
1056 HDC hdcScreen
= NULL
;
1058 HBITMAP hbmpOld
, hbmpRet
= NULL
;
1063 /* Map the bitmap info */
1064 if(fuLoad
& LR_LOADFROMFILE
)
1066 const BITMAPFILEHEADER
* pbmfh
;
1068 pvMapping
= map_fileW(lpszName
, NULL
);
1072 if (pbmfh
->bfType
!= 0x4d42 /* 'BM' */)
1074 WARN("Invalid/unsupported bitmap format!\n");
1077 pbmi
= (const BITMAPINFO
*)(pbmfh
+ 1);
1079 /* Get the image bits */
1080 if(pbmfh
->bfOffBits
)
1081 dwOffset
= pbmfh
->bfOffBits
- sizeof(BITMAPFILEHEADER
);
1087 /* Caller wants an OEM bitmap */
1089 hinst
= User32Instance
;
1090 hrsrc
= FindResourceW(hinst
, lpszName
, RT_BITMAP
);
1093 hgRsrc
= LoadResource(hinst
, hrsrc
);
1096 pbmi
= LockResource(hgRsrc
);
1102 if(DIB_GetBitmapInfo(&pbmi
->bmiHeader
, &width
, &height
, &bpp
, &compr
) == -1)
1104 if((width
> 65535) || (height
> 65535))
1111 cyDesired
= -cyDesired
;
1113 iBMISize
= bitmap_info_size(pbmi
, DIB_RGB_COLORS
);
1115 /* Get a pointer to the image data */
1116 pvBits
= (char*)pbmi
+ (dwOffset
? dwOffset
: iBMISize
);
1118 /* Create a copy of the info describing the bitmap in the file */
1119 pbmiCopy
= HeapAlloc(GetProcessHeap(), 0, iBMISize
);
1122 CopyMemory(pbmiCopy
, pbmi
, iBMISize
);
1124 /* Fix it up, if needed */
1125 if(fuLoad
& (LR_LOADTRANSPARENT
| LR_LOADMAP3DCOLORS
))
1127 WORD bpp
, incr
, numColors
;
1130 COLORREF crWindow
, cr3DShadow
, cr3DFace
, cr3DLight
;
1131 BYTE pixel
= *((BYTE
*)pvBits
);
1134 if(pbmiCopy
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
1136 bpp
= ((BITMAPCOREHEADER
*)&pbmiCopy
->bmiHeader
)->bcBitCount
;
1137 numColors
= 1 << bpp
;
1138 /* BITMAPCOREINFO holds RGBTRIPLEs */
1143 bpp
= pbmiCopy
->bmiHeader
.biBitCount
;
1144 /* BITMAPINFOHEADER holds RGBQUADs */
1146 numColors
= pbmiCopy
->bmiHeader
.biClrUsed
;
1147 if(numColors
> 256) numColors
= 256;
1148 if (!numColors
&& (bpp
<= 8)) numColors
= 1 << bpp
;
1154 pbmiColors
= (char*)pbmiCopy
+ pbmiCopy
->bmiHeader
.biSize
;
1156 /* Get the relevant colors */
1157 crWindow
= GetSysColor(COLOR_WINDOW
);
1158 cr3DShadow
= GetSysColor(COLOR_3DSHADOW
);
1159 cr3DFace
= GetSysColor(COLOR_3DFACE
);
1160 cr3DLight
= GetSysColor(COLOR_3DLIGHT
);
1162 /* Fix the transparent palette entry */
1163 if(fuLoad
& LR_LOADTRANSPARENT
)
1167 case 1: pixel
>>= 7; break;
1168 case 4: pixel
>>= 4; break;
1171 FIXME("Unhandled bit depth %d.\n", bpp
);
1175 if(pixel
>= numColors
)
1177 ERR("Wrong pixel passed in.\n");
1181 /* If both flags are set, we must use COLOR_3DFACE */
1182 if(fuLoad
& LR_LOADMAP3DCOLORS
) crWindow
= cr3DFace
;
1184 /* Define the color */
1185 ptr
= (RGBTRIPLE
*)(pbmiColors
+ pixel
*incr
);
1186 ptr
->rgbtBlue
= GetBValue(crWindow
);
1187 ptr
->rgbtGreen
= GetGValue(crWindow
);
1188 ptr
->rgbtRed
= GetRValue(crWindow
);
1192 /* If we are here, then LR_LOADMAP3DCOLORS is set without LR_TRANSPARENT */
1193 for(i
= 0; i
<numColors
; i
++)
1195 ptr
= (RGBTRIPLE
*)(pbmiColors
+ i
*incr
);
1196 if((ptr
->rgbtBlue
== ptr
->rgbtRed
) && (ptr
->rgbtBlue
== ptr
->rgbtGreen
))
1198 if(ptr
->rgbtBlue
== 128)
1200 ptr
->rgbtBlue
= GetBValue(cr3DShadow
);
1201 ptr
->rgbtGreen
= GetGValue(cr3DShadow
);
1202 ptr
->rgbtRed
= GetRValue(cr3DShadow
);
1204 if(ptr
->rgbtBlue
== 192)
1206 ptr
->rgbtBlue
= GetBValue(cr3DFace
);
1207 ptr
->rgbtGreen
= GetGValue(cr3DFace
);
1208 ptr
->rgbtRed
= GetRValue(cr3DFace
);
1210 if(ptr
->rgbtBlue
== 223)
1212 ptr
->rgbtBlue
= GetBValue(cr3DLight
);
1213 ptr
->rgbtGreen
= GetGValue(cr3DLight
);
1214 ptr
->rgbtRed
= GetRValue(cr3DLight
);
1221 if(fuLoad
& LR_CREATEDIBSECTION
)
1223 /* Allocate the BMI describing the new bitmap */
1224 pbmiScaled
= HeapAlloc(GetProcessHeap(), 0, iBMISize
);
1227 CopyMemory(pbmiScaled
, pbmiCopy
, iBMISize
);
1230 if(pbmiScaled
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
1232 BITMAPCOREHEADER
* pbmch
= (BITMAPCOREHEADER
*)&pbmiScaled
->bmiHeader
;
1233 pbmch
->bcWidth
= cxDesired
;
1234 pbmch
->bcHeight
= cyDesired
;
1238 pbmiScaled
->bmiHeader
.biWidth
= cxDesired
;
1239 pbmiScaled
->bmiHeader
.biHeight
= cyDesired
;
1240 /* No compression for DIB sections */
1241 pbmiScaled
->bmiHeader
.biCompression
= BI_RGB
;
1245 /* Top-down image */
1246 if(cyDesired
< 0) cyDesired
= -cyDesired
;
1248 /* We need a device context */
1249 hdcScreen
= CreateDCW(DISPLAYW
, NULL
, NULL
, NULL
);
1252 hdc
= CreateCompatibleDC(hdcScreen
);
1256 /* Now create the bitmap */
1257 if(fuLoad
& LR_CREATEDIBSECTION
)
1258 hbmpRet
= CreateDIBSection(hdc
, pbmiScaled
, DIB_RGB_COLORS
, NULL
, 0, 0);
1261 if(is_dib_monochrome(pbmiCopy
) || (fuLoad
& LR_MONOCHROME
))
1262 hbmpRet
= CreateBitmap(cxDesired
, cyDesired
, 1, 1, NULL
);
1264 hbmpRet
= CreateCompatibleBitmap(hdcScreen
, cxDesired
, cyDesired
);
1270 hbmpOld
= SelectObject(hdc
, hbmpRet
);
1273 if(!StretchDIBits(hdc
, 0, 0, cxDesired
, cyDesired
,
1274 0, 0, pbmi
->bmiHeader
.biWidth
, pbmi
->bmiHeader
.biHeight
,
1275 pvBits
, pbmiCopy
, DIB_RGB_COLORS
, SRCCOPY
))
1277 ERR("StretchDIBits failed!.\n");
1278 SelectObject(hdc
, hbmpOld
);
1279 DeleteObject(hbmpRet
);
1284 SelectObject(hdc
, hbmpOld
);
1288 DeleteDC(hdcScreen
);
1292 HeapFree(GetProcessHeap(), 0, pbmiScaled
);
1294 HeapFree(GetProcessHeap(), 0, pbmiCopy
);
1296 UnmapViewOfFile( pvMapping
);
1298 FreeResource(hgRsrc
);
1306 CURSORICON_LoadFromFileW(
1307 _In_ LPCWSTR lpszName
,
1314 const CURSORICONFILEDIRENTRY
*entry
;
1315 const CURSORICONFILEDIR
*dir
;
1318 HANDLE hCurIcon
= NULL
;
1319 CURSORDATA cursorData
;
1321 TRACE("loading %s\n", debugstr_w( lpszName
));
1323 bits
= map_fileW( lpszName
, &filesize
);
1327 /* Check for .ani. */
1328 if (memcmp( bits
, "RIFF", 4 ) == 0)
1334 dir
= (CURSORICONFILEDIR
*) bits
;
1335 entry
= get_best_icon_file_entry(dir
, filesize
, cxDesired
, cyDesired
, bIcon
, fuLoad
);
1339 /* Fix dimensions */
1340 if(!cxDesired
) cxDesired
= entry
->bWidth
;
1341 if(!cyDesired
) cyDesired
= entry
->bHeight
;
1342 /* A bit of preparation */
1343 ZeroMemory(&cursorData
, sizeof(cursorData
));
1346 cursorData
.xHotspot
= entry
->xHotspot
;
1347 cursorData
.yHotspot
= entry
->yHotspot
;
1349 cursorData
.rt
= (USHORT
)((ULONG_PTR
)(bIcon
? RT_ICON
: RT_CURSOR
));
1352 if(!CURSORICON_GetCursorDataFromBMI(&cursorData
, (BITMAPINFO
*)(&bits
[entry
->dwDIBOffset
])))
1355 hCurIcon
= NtUserxCreateEmptyCurObject(FALSE
);
1360 if(!NtUserSetCursorIconData(hCurIcon
, NULL
, NULL
, &cursorData
))
1362 NtUserDestroyCursor(hCurIcon
, TRUE
);
1367 UnmapViewOfFile(bits
);
1372 DeleteObject(cursorData
.hbmMask
);
1373 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
1374 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
1375 UnmapViewOfFile(bits
);
1382 CURSORICON_LoadImageW(
1383 _In_opt_ HINSTANCE hinst
,
1384 _In_ LPCWSTR lpszName
,
1392 HANDLE handle
, hCurIcon
= NULL
;
1396 CURSORDATA cursorData
;
1398 UNICODE_STRING ustrRsrc
;
1399 UNICODE_STRING ustrModule
= {0, 0, NULL
};
1401 /* Fix width/height */
1402 if(fuLoad
& LR_DEFAULTSIZE
)
1404 if(!cxDesired
) cxDesired
= GetSystemMetrics(bIcon
? SM_CXICON
: SM_CXCURSOR
);
1405 if(!cyDesired
) cyDesired
= GetSystemMetrics(bIcon
? SM_CYICON
: SM_CYCURSOR
);
1408 if(fuLoad
& LR_LOADFROMFILE
)
1410 return CURSORICON_LoadFromFileW(lpszName
, cxDesired
, cyDesired
, fuLoad
, bIcon
);
1413 /* Check if caller wants OEM icons */
1415 hinst
= User32Instance
;
1417 if(fuLoad
& LR_SHARED
)
1419 DWORD size
= MAX_PATH
;
1420 FINDEXISTINGCURICONPARAM param
;
1422 TRACE("Checking for an LR_SHARED cursor/icon.\n");
1423 /* Prepare the resource name string */
1424 if(IS_INTRESOURCE(lpszName
))
1426 ustrRsrc
.Buffer
= (LPWSTR
)lpszName
;
1427 ustrRsrc
.Length
= 0;
1428 ustrRsrc
.MaximumLength
= 0;
1431 RtlInitUnicodeString(&ustrRsrc
, lpszName
);
1433 /* Get the module name string */
1437 ustrModule
.Buffer
= HeapAlloc(GetProcessHeap(), 0, size
*sizeof(WCHAR
));
1438 if (!ustrModule
.Buffer
)
1440 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1443 ret
= GetModuleFileNameW(hinst
, ustrModule
.Buffer
, size
);
1446 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1450 /* This API is completely broken... */
1453 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1458 ustrModule
.Buffer
[ret
] = UNICODE_NULL
;
1459 ustrModule
.Length
= ret
* sizeof(WCHAR
);
1460 ustrModule
.MaximumLength
= size
* sizeof(WCHAR
);
1465 param
.bIcon
= bIcon
;
1466 param
.cx
= cxDesired
;
1467 param
.cy
= cyDesired
;
1468 hCurIcon
= NtUserFindExistingCursorIcon(&ustrModule
, &ustrRsrc
, ¶m
);
1471 /* Woohoo, got it! */
1473 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1478 /* Find resource ID */
1479 hrsrc
= FindResourceW(
1482 bIcon
? RT_GROUP_ICON
: RT_GROUP_CURSOR
);
1484 /* We let FindResource, LoadResource, etc. call SetLastError */
1488 handle
= LoadResource(hinst
, hrsrc
);
1492 dir
= LockResource(handle
);
1496 wResId
= LookupIconIdFromDirectoryEx((PBYTE
)dir
, bIcon
, cxDesired
, cyDesired
, fuLoad
);
1497 FreeResource(handle
);
1499 /* Get the relevant resource pointer */
1500 hrsrc
= FindResourceW(
1502 MAKEINTRESOURCEW(wResId
),
1503 bIcon
? RT_ICON
: RT_CURSOR
);
1507 handle
= LoadResource(hinst
, hrsrc
);
1511 bits
= LockResource(handle
);
1514 FreeResource(handle
);
1518 ZeroMemory(&cursorData
, sizeof(cursorData
));
1520 /* This is from resource */
1521 cursorData
.CURSORF_flags
= CURSORF_FROMRESOURCE
;
1523 if(dir
->idType
== 2)
1525 /* idType == 2 for cursor resources */
1526 SHORT
* ptr
= (SHORT
*)bits
;
1527 cursorData
.xHotspot
= ptr
[0];
1528 cursorData
.yHotspot
= ptr
[1];
1529 bits
+= 2*sizeof(SHORT
);
1531 cursorData
.cx
= cxDesired
;
1532 cursorData
.cy
= cyDesired
;
1533 cursorData
.rt
= (USHORT
)((ULONG_PTR
)(bIcon
? RT_ICON
: RT_CURSOR
));
1535 /* Get the bitmaps */
1536 bStatus
= CURSORICON_GetCursorDataFromBMI(
1540 FreeResource( handle
);
1545 /* Create the handle */
1546 hCurIcon
= NtUserxCreateEmptyCurObject(FALSE
);
1553 if(fuLoad
& LR_SHARED
)
1555 cursorData
.CURSORF_flags
|= CURSORF_LRSHARED
;
1556 bStatus
= NtUserSetCursorIconData(hCurIcon
, &ustrModule
, &ustrRsrc
, &cursorData
);
1559 bStatus
= NtUserSetCursorIconData(hCurIcon
, NULL
, NULL
, &cursorData
);
1563 NtUserDestroyCursor(hCurIcon
, TRUE
);
1568 if(ustrModule
.Buffer
)
1569 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1573 if(ustrModule
.Buffer
)
1574 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1575 DeleteObject(cursorData
.hbmMask
);
1576 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
1577 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
1596 objSize
= GetObjectW( hnd
, sizeof(ds
), &ds
);
1597 if (!objSize
) return 0;
1598 if ((desiredx
< 0) || (desiredy
< 0)) return 0;
1600 if (flags
& LR_COPYFROMRESOURCE
)
1602 FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
1605 if (flags
& LR_COPYRETURNORG
)
1607 FIXME("The flag LR_COPYRETURNORG is not implemented for bitmaps\n");
1610 if (desiredx
== 0) desiredx
= ds
.dsBm
.bmWidth
;
1611 if (desiredy
== 0) desiredy
= ds
.dsBm
.bmHeight
;
1613 /* Allocate memory for a BITMAPINFOHEADER structure and a
1614 color table. The maximum number of colors in a color table
1615 is 256 which corresponds to a bitmap with depth 8.
1616 Bitmaps with higher depths don't have color tables. */
1617 bi
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
));
1620 bi
->bmiHeader
.biSize
= sizeof(bi
->bmiHeader
);
1621 bi
->bmiHeader
.biPlanes
= ds
.dsBm
.bmPlanes
;
1622 bi
->bmiHeader
.biBitCount
= ds
.dsBm
.bmBitsPixel
;
1623 bi
->bmiHeader
.biCompression
= BI_RGB
;
1625 if (flags
& LR_CREATEDIBSECTION
)
1627 /* Create a DIB section. LR_MONOCHROME is ignored */
1629 HDC dc
= CreateCompatibleDC(NULL
);
1631 if (objSize
== sizeof(DIBSECTION
))
1633 /* The source bitmap is a DIB.
1634 Get its attributes to create an exact copy */
1635 memcpy(bi
, &ds
.dsBmih
, sizeof(BITMAPINFOHEADER
));
1638 bi
->bmiHeader
.biWidth
= desiredx
;
1639 bi
->bmiHeader
.biHeight
= desiredy
;
1641 /* Get the color table or the color masks */
1642 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
1644 res
= CreateDIBSection(dc
, bi
, DIB_RGB_COLORS
, &bits
, NULL
, 0);
1649 /* Create a device-dependent bitmap */
1651 BOOL monochrome
= (flags
& LR_MONOCHROME
);
1653 if (objSize
== sizeof(DIBSECTION
))
1655 /* The source bitmap is a DIB section.
1656 Get its attributes */
1657 HDC dc
= CreateCompatibleDC(NULL
);
1658 bi
->bmiHeader
.biWidth
= ds
.dsBm
.bmWidth
;
1659 bi
->bmiHeader
.biHeight
= ds
.dsBm
.bmHeight
;
1660 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
1663 if (!monochrome
&& ds
.dsBm
.bmBitsPixel
== 1)
1665 /* Look if the colors of the DIB are black and white */
1668 (bi
->bmiColors
[0].rgbRed
== 0xff
1669 && bi
->bmiColors
[0].rgbGreen
== 0xff
1670 && bi
->bmiColors
[0].rgbBlue
== 0xff
1671 && bi
->bmiColors
[0].rgbReserved
== 0
1672 && bi
->bmiColors
[1].rgbRed
== 0
1673 && bi
->bmiColors
[1].rgbGreen
== 0
1674 && bi
->bmiColors
[1].rgbBlue
== 0
1675 && bi
->bmiColors
[1].rgbReserved
== 0)
1677 (bi
->bmiColors
[0].rgbRed
== 0
1678 && bi
->bmiColors
[0].rgbGreen
== 0
1679 && bi
->bmiColors
[0].rgbBlue
== 0
1680 && bi
->bmiColors
[0].rgbReserved
== 0
1681 && bi
->bmiColors
[1].rgbRed
== 0xff
1682 && bi
->bmiColors
[1].rgbGreen
== 0xff
1683 && bi
->bmiColors
[1].rgbBlue
== 0xff
1684 && bi
->bmiColors
[1].rgbReserved
== 0);
1687 else if (!monochrome
)
1689 monochrome
= ds
.dsBm
.bmBitsPixel
== 1;
1694 res
= CreateBitmap(desiredx
, desiredy
, 1, 1, NULL
);
1698 HDC screenDC
= GetDC(NULL
);
1699 res
= CreateCompatibleBitmap(screenDC
, desiredx
, desiredy
);
1700 ReleaseDC(NULL
, screenDC
);
1706 /* Only copy the bitmap if it's a DIB section or if it's
1707 compatible to the screen */
1710 if (objSize
== sizeof(DIBSECTION
))
1712 copyContents
= TRUE
;
1716 HDC screenDC
= GetDC(NULL
);
1717 int screen_depth
= GetDeviceCaps(screenDC
, BITSPIXEL
);
1718 ReleaseDC(NULL
, screenDC
);
1720 copyContents
= (ds
.dsBm
.bmBitsPixel
== 1 || ds
.dsBm
.bmBitsPixel
== screen_depth
);
1725 /* The source bitmap may already be selected in a device context,
1726 use GetDIBits/StretchDIBits and not StretchBlt */
1731 dc
= CreateCompatibleDC(NULL
);
1733 bi
->bmiHeader
.biWidth
= ds
.dsBm
.bmWidth
;
1734 bi
->bmiHeader
.biHeight
= ds
.dsBm
.bmHeight
;
1735 bi
->bmiHeader
.biSizeImage
= 0;
1736 bi
->bmiHeader
.biClrUsed
= 0;
1737 bi
->bmiHeader
.biClrImportant
= 0;
1739 /* Fill in biSizeImage */
1740 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, NULL
, bi
, DIB_RGB_COLORS
);
1741 bits
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, bi
->bmiHeader
.biSizeImage
);
1747 /* Get the image bits of the source bitmap */
1748 GetDIBits(dc
, hnd
, 0, ds
.dsBm
.bmHeight
, bits
, bi
, DIB_RGB_COLORS
);
1750 /* Copy it to the destination bitmap */
1751 oldBmp
= SelectObject(dc
, res
);
1752 StretchDIBits(dc
, 0, 0, desiredx
, desiredy
,
1753 0, 0, ds
.dsBm
.bmWidth
, ds
.dsBm
.bmHeight
,
1754 bits
, bi
, DIB_RGB_COLORS
, SRCCOPY
);
1755 SelectObject(dc
, oldBmp
);
1757 HeapFree(GetProcessHeap(), 0, bits
);
1763 if (flags
& LR_COPYDELETEORG
)
1768 HeapFree(GetProcessHeap(), 0, bi
);
1774 CURSORICON_CopyImage(
1784 CURSORDATA CursorData
;
1786 if (fuFlags
& LR_COPYFROMRESOURCE
)
1788 /* Get the icon module/resource names */
1789 UNICODE_STRING ustrModule
;
1790 UNICODE_STRING ustrRsrc
;
1793 ustrModule
.MaximumLength
= 0;
1794 ustrRsrc
.MaximumLength
= 0;
1796 /* Get the buffer size */
1797 if (!NtUserGetIconInfo(hicon
, NULL
, &ustrModule
, &ustrRsrc
, NULL
, FALSE
))
1802 ustrModule
.Buffer
= HeapAlloc(GetProcessHeap(), 0, ustrModule
.MaximumLength
);
1803 if (!ustrModule
.Buffer
)
1805 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1809 if (ustrRsrc
.MaximumLength
)
1811 ustrRsrc
.Buffer
= HeapAlloc(GetProcessHeap(), 0, ustrRsrc
.MaximumLength
);
1812 if (!ustrRsrc
.Buffer
)
1814 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1815 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1820 if (!NtUserGetIconInfo(hicon
, NULL
, &ustrModule
, &ustrRsrc
, NULL
, FALSE
))
1822 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1823 if (!IS_INTRESOURCE(ustrRsrc
.Buffer
))
1824 HeapFree(GetProcessHeap(), 0, ustrRsrc
.Buffer
);
1828 /* NULL-terminate our strings */
1829 ustrModule
.Buffer
[ustrModule
.Length
/sizeof(WCHAR
)] = UNICODE_NULL
;
1830 if (!IS_INTRESOURCE(ustrRsrc
.Buffer
))
1831 ustrRsrc
.Buffer
[ustrRsrc
.Length
/sizeof(WCHAR
)] = UNICODE_NULL
;
1833 TRACE("Got module %S, resource %p (%S).\n", ustrModule
.Buffer
,
1834 ustrRsrc
.Buffer
, IS_INTRESOURCE(ustrRsrc
.Buffer
) ? L
"" : ustrRsrc
.Buffer
);
1836 /* Get the module handle */
1837 if (!GetModuleHandleExW(0, ustrModule
.Buffer
, &hModule
))
1839 /* This should never happen */
1840 ERR("Invalid handle?.\n");
1841 SetLastError(ERROR_INVALID_PARAMETER
);
1845 /* Call the relevant function */
1846 ret
= CURSORICON_LoadImageW(
1851 fuFlags
& (LR_DEFAULTSIZE
| LR_SHARED
),
1854 FreeLibrary(hModule
);
1856 /* If we're here, that means that the passed icon is shared. Don't destroy it, even if LR_COPYDELETEORG is specified */
1858 HeapFree(GetProcessHeap(), 0, ustrModule
.Buffer
);
1859 if (!IS_INTRESOURCE(ustrRsrc
.Buffer
))
1860 HeapFree(GetProcessHeap(), 0, ustrRsrc
.Buffer
);
1862 TRACE("Returning 0x%08x.\n", ret
);
1867 /* This is a regular copy */
1868 if (fuFlags
& ~(LR_COPYDELETEORG
| LR_SHARED
))
1869 FIXME("Unimplemented flags: 0x%08x\n", fuFlags
);
1871 if (!GetIconInfo(hicon
, &ii
))
1873 ERR("GetIconInfo failed.\n");
1877 /* This is CreateIconIndirect with the LR_SHARED coat added */
1878 if (!CURSORICON_GetCursorDataFromIconInfo(&CursorData
, &ii
))
1881 if (fuFlags
& LR_SHARED
)
1882 CursorData
.CURSORF_flags
|= CURSORF_LRSHARED
;
1884 ret
= NtUserxCreateEmptyCurObject(FALSE
);
1888 if (!NtUserSetCursorIconData(ret
, NULL
, NULL
, &CursorData
))
1890 NtUserDestroyCursor(ret
, TRUE
);
1895 DeleteObject(ii
.hbmMask
);
1896 if (ii
.hbmColor
) DeleteObject(ii
.hbmColor
);
1898 if (ret
&& (fuFlags
& LR_COPYDELETEORG
))
1905 User32CallCopyImageFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
1907 PCOPYIMAGE_CALLBACK_ARGUMENTS Common
;
1909 Common
= (PCOPYIMAGE_CALLBACK_ARGUMENTS
) Arguments
;
1911 Result
= CopyImage(Common
->hImage
,
1917 return ZwCallbackReturn(&Result
, sizeof(HANDLE
), STATUS_SUCCESS
);
1921 /************* PUBLIC FUNCTIONS *******************/
1923 HANDLE WINAPI
CopyImage(
1931 TRACE("hImage=%p, uType=%u, cxDesired=%d, cyDesired=%d, fuFlags=%x\n",
1932 hImage
, uType
, cxDesired
, cyDesired
, fuFlags
);
1936 return BITMAP_CopyImage(hImage
, cxDesired
, cyDesired
, fuFlags
);
1939 return CURSORICON_CopyImage(hImage
, uType
== IMAGE_ICON
, cxDesired
, cyDesired
, fuFlags
);
1941 SetLastError(ERROR_INVALID_PARAMETER
);
1947 HICON WINAPI
CopyIcon(
1951 return CURSORICON_CopyImage(hIcon
, FALSE
, 0, 0, 0);
1954 BOOL WINAPI
DrawIcon(
1961 return DrawIconEx(hDC
, X
, Y
, hIcon
, 0, 0, 0, NULL
, DI_NORMAL
| DI_COMPAT
| DI_DEFAULTSIZE
);
1964 BOOL WINAPI
DrawIconEx(
1971 _In_ UINT istepIfAniCur
,
1972 _In_opt_ HBRUSH hbrFlickerFreeDraw
,
1976 return NtUserDrawIconEx(hdc
, xLeft
, yTop
, hIcon
, cxWidth
, cyWidth
,
1977 istepIfAniCur
, hbrFlickerFreeDraw
, diFlags
,
1981 BOOL WINAPI
GetIconInfo(
1983 _Out_ PICONINFO piconinfo
1986 return NtUserGetIconInfo(hIcon
, piconinfo
, NULL
, NULL
, NULL
, FALSE
);
1989 BOOL WINAPI
DestroyIcon(
1993 return NtUserDestroyCursor(hIcon
, FALSE
);
1996 HICON WINAPI
LoadIconA(
1997 _In_opt_ HINSTANCE hInstance
,
1998 _In_ LPCSTR lpIconName
2001 TRACE("%p, %s\n", hInstance
, debugstr_a(lpIconName
));
2003 return LoadImageA(hInstance
,
2008 LR_SHARED
| LR_DEFAULTSIZE
);
2011 HICON WINAPI
LoadIconW(
2012 _In_opt_ HINSTANCE hInstance
,
2013 _In_ LPCWSTR lpIconName
2016 TRACE("%p, %s\n", hInstance
, debugstr_w(lpIconName
));
2018 return LoadImageW(hInstance
,
2023 LR_SHARED
| LR_DEFAULTSIZE
);
2026 HCURSOR WINAPI
LoadCursorA(
2027 _In_opt_ HINSTANCE hInstance
,
2028 _In_ LPCSTR lpCursorName
2031 TRACE("%p, %s\n", hInstance
, debugstr_a(lpCursorName
));
2033 return LoadImageA(hInstance
,
2038 LR_SHARED
| LR_DEFAULTSIZE
);
2041 HCURSOR WINAPI
LoadCursorW(
2042 _In_opt_ HINSTANCE hInstance
,
2043 _In_ LPCWSTR lpCursorName
2046 TRACE("%p, %s\n", hInstance
, debugstr_w(lpCursorName
));
2048 return LoadImageW(hInstance
,
2053 LR_SHARED
| LR_DEFAULTSIZE
);
2056 HCURSOR WINAPI
LoadCursorFromFileA(
2057 _In_ LPCSTR lpFileName
2060 TRACE("%s\n", debugstr_a(lpFileName
));
2062 return LoadImageA(NULL
,
2067 LR_LOADFROMFILE
| LR_DEFAULTSIZE
);
2070 HCURSOR WINAPI
LoadCursorFromFileW(
2071 _In_ LPCWSTR lpFileName
2074 TRACE("%s\n", debugstr_w(lpFileName
));
2076 return LoadImageW(NULL
,
2081 LR_LOADFROMFILE
| LR_DEFAULTSIZE
);
2084 HBITMAP WINAPI
LoadBitmapA(
2085 _In_opt_ HINSTANCE hInstance
,
2086 _In_ LPCSTR lpBitmapName
2089 TRACE("%p, %s\n", hInstance
, debugstr_a(lpBitmapName
));
2091 return LoadImageA(hInstance
,
2099 HBITMAP WINAPI
LoadBitmapW(
2100 _In_opt_ HINSTANCE hInstance
,
2101 _In_ LPCWSTR lpBitmapName
2104 TRACE("%p, %s\n", hInstance
, debugstr_w(lpBitmapName
));
2106 return LoadImageW(hInstance
,
2114 HANDLE WINAPI
LoadImageA(
2115 _In_opt_ HINSTANCE hinst
,
2116 _In_ LPCSTR lpszName
,
2127 if (IS_INTRESOURCE(lpszName
))
2128 return LoadImageW(hinst
, (LPCWSTR
)lpszName
, uType
, cxDesired
, cyDesired
, fuLoad
);
2130 len
= MultiByteToWideChar( CP_ACP
, 0, lpszName
, -1, NULL
, 0 );
2131 u_name
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
2132 MultiByteToWideChar( CP_ACP
, 0, lpszName
, -1, u_name
, len
);
2134 res
= LoadImageW(hinst
, u_name
, uType
, cxDesired
, cyDesired
, fuLoad
);
2135 HeapFree(GetProcessHeap(), 0, u_name
);
2139 HANDLE WINAPI
LoadImageW(
2140 _In_opt_ HINSTANCE hinst
,
2141 _In_ LPCWSTR lpszName
,
2148 TRACE("hinst 0x%p, name %s, uType 0x%08x, cxDesired %d, cyDesired %d, fuLoad 0x%08x.\n",
2149 hinst
, debugstr_w(lpszName
), uType
, cxDesired
, cyDesired
, fuLoad
);
2150 /* Redirect to each implementation */
2154 return BITMAP_LoadImageW(hinst
, lpszName
, cxDesired
, cyDesired
, fuLoad
);
2157 return CURSORICON_LoadImageW(hinst
, lpszName
, cxDesired
, cyDesired
, fuLoad
, uType
== IMAGE_ICON
);
2159 SetLastError(ERROR_INVALID_PARAMETER
);
2165 int WINAPI
LookupIconIdFromDirectory(
2166 _In_ PBYTE presbits
,
2170 return LookupIconIdFromDirectoryEx( presbits
, fIcon
,
2171 fIcon
? GetSystemMetrics(SM_CXICON
) : GetSystemMetrics(SM_CXCURSOR
),
2172 fIcon
? GetSystemMetrics(SM_CYICON
) : GetSystemMetrics(SM_CYCURSOR
), fIcon
? 0 : LR_MONOCHROME
);
2175 int WINAPI
LookupIconIdFromDirectoryEx(
2176 _In_ PBYTE presbits
,
2184 CURSORICONDIR
* dir
= (CURSORICONDIR
*)presbits
;
2185 CURSORICONDIRENTRY
* entry
;
2186 int i
, numMatch
= 0, iIndex
= -1;
2187 WORD width
, height
, BitCount
= 0;
2188 BOOL notPaletted
= FALSE
;
2189 ULONG bestScore
= 0xFFFFFFFF, score
;
2191 TRACE("%p, %x, %i, %i, %x.\n", presbits
, fIcon
, cxDesired
, cyDesired
, Flags
);
2193 if(!(dir
&& !dir
->idReserved
&& (dir
->idType
& 3)))
2195 WARN("Invalid resource.\n");
2199 if(Flags
& LR_MONOCHROME
)
2204 icScreen
= CreateICW(DISPLAYW
, NULL
, NULL
, NULL
);
2208 bppDesired
= GetDeviceCaps(icScreen
, BITSPIXEL
);
2213 cxDesired
= Flags
& LR_DEFAULTSIZE
? GetSystemMetrics(fIcon
? SM_CXICON
: SM_CXCURSOR
) : 256;
2215 cyDesired
= Flags
& LR_DEFAULTSIZE
? GetSystemMetrics(fIcon
? SM_CYICON
: SM_CYCURSOR
) : 256;
2217 /* Find the best match for the desired size */
2218 for(i
= 0; i
< dir
->idCount
; i
++)
2220 entry
= &dir
->idEntries
[i
];
2221 width
= fIcon
? entry
->ResInfo
.icon
.bWidth
: entry
->ResInfo
.cursor
.wWidth
;
2222 /* Height is twice as big in cursor resources */
2223 height
= fIcon
? entry
->ResInfo
.icon
.bHeight
: entry
->ResInfo
.cursor
.wHeight
/2;
2224 /* 0 represents 256 */
2225 if(!width
) width
= 256;
2226 if(!height
) height
= 256;
2227 /* Calculate the "score" (lower is better) */
2228 score
= 2*(abs(width
- cxDesired
) + abs(height
- cyDesired
));
2229 if( score
> bestScore
)
2231 /* Bigger than requested lowers the score */
2232 if(width
> cxDesired
)
2233 score
-= width
- cxDesired
;
2234 if(height
> cyDesired
)
2235 score
-= height
- cyDesired
;
2236 if(score
> bestScore
)
2238 if(score
== bestScore
)
2240 if(entry
->wBitCount
> BitCount
)
2241 BitCount
= entry
->wBitCount
;
2248 BitCount
= entry
->wBitCount
;
2253 /* Only one entry fits the asked dimensions */
2254 return dir
->idEntries
[iIndex
].wResId
;
2257 /* Avoid paletted icons on non-paletted device */
2258 if (bppDesired
> 8 && BitCount
> 8)
2263 /* Now find the entry with the best depth */
2264 for(i
= 0; i
< dir
->idCount
; i
++)
2266 entry
= &dir
->idEntries
[i
];
2267 width
= fIcon
? entry
->ResInfo
.icon
.bWidth
: entry
->ResInfo
.cursor
.wWidth
;
2268 height
= fIcon
? entry
->ResInfo
.icon
.bHeight
: entry
->ResInfo
.cursor
.wHeight
/2;
2269 /* 0 represents 256 */
2270 if(!width
) width
= 256;
2271 if(!height
) height
= 256;
2272 /* Check if this is the best match we had */
2273 score
= 2*(abs(width
- cxDesired
) + abs(height
- cyDesired
));
2274 if(width
> cxDesired
)
2275 score
-= width
- cxDesired
;
2276 if(height
> cyDesired
)
2277 score
-= height
- cyDesired
;
2278 if(score
!= bestScore
)
2281 if(entry
->wBitCount
== bppDesired
)
2282 return entry
->wResId
;
2283 /* We take the highest possible but smaller than the display depth */
2284 if((entry
->wBitCount
> BitCount
) && (entry
->wBitCount
< bppDesired
))
2286 /* Avoid paletted icons on non paletted devices */
2287 if ((entry
->wBitCount
<= 8) && notPaletted
)
2290 BitCount
= entry
->wBitCount
;
2295 return dir
->idEntries
[iIndex
].wResId
;
2297 /* No inferior or equal depth available. Get the smallest bigger one */
2300 for(i
= 0; i
< dir
->idCount
; i
++)
2302 entry
= &dir
->idEntries
[i
];
2303 width
= fIcon
? entry
->ResInfo
.icon
.bWidth
: entry
->ResInfo
.cursor
.wWidth
;
2304 height
= fIcon
? entry
->ResInfo
.icon
.bHeight
: entry
->ResInfo
.cursor
.wHeight
/2;
2305 /* 0 represents 256 */
2306 if(!width
) width
= 256;
2307 if(!height
) height
= 256;
2308 /* Check if this is the best match we had */
2309 score
= 2*(abs(width
- cxDesired
) + abs(height
- cyDesired
));
2310 if(width
> cxDesired
)
2311 score
-= width
- cxDesired
;
2312 if(height
> cyDesired
)
2313 score
-= height
- cyDesired
;
2314 if(score
!= bestScore
)
2316 /* Check the bit depth */
2317 if(entry
->wBitCount
< BitCount
)
2319 if((entry
->wBitCount
<= 8) && notPaletted
)
2322 BitCount
= entry
->wBitCount
;
2326 return dir
->idEntries
[iIndex
].wResId
;
2331 HICON WINAPI
CreateIcon(
2332 _In_opt_ HINSTANCE hInstance
,
2336 _In_ BYTE cBitsPixel
,
2337 _In_
const BYTE
*lpbANDbits
,
2338 _In_
const BYTE
*lpbXORbits
2344 TRACE_(icon
)("%dx%d, planes %d, bpp %d, xor %p, and %p\n",
2345 nWidth
, nHeight
, cPlanes
, cBitsPixel
, lpbXORbits
, lpbANDbits
);
2348 iinfo
.xHotspot
= nWidth
/ 2;
2349 iinfo
.yHotspot
= nHeight
/ 2;
2350 if (cPlanes
* cBitsPixel
> 1)
2352 iinfo
.hbmColor
= CreateBitmap( nWidth
, nHeight
, cPlanes
, cBitsPixel
, lpbXORbits
);
2353 iinfo
.hbmMask
= CreateBitmap( nWidth
, nHeight
, 1, 1, lpbANDbits
);
2357 iinfo
.hbmMask
= CreateBitmap( nWidth
, nHeight
* 2, 1, 1, lpbANDbits
);
2358 iinfo
.hbmColor
= NULL
;
2361 hIcon
= CreateIconIndirect( &iinfo
);
2363 DeleteObject( iinfo
.hbmMask
);
2364 if (iinfo
.hbmColor
) DeleteObject( iinfo
.hbmColor
);
2369 HICON WINAPI
CreateIconFromResource(
2370 _In_ PBYTE presbits
,
2371 _In_ DWORD dwResSize
,
2376 return CreateIconFromResourceEx( presbits
, dwResSize
, fIcon
, dwVer
, 0, 0, LR_DEFAULTSIZE
| LR_SHARED
);
2379 HICON WINAPI
CreateIconFromResourceEx(
2380 _In_ PBYTE pbIconBits
,
2381 _In_ DWORD cbIconBits
,
2383 _In_ DWORD dwVersion
,
2389 CURSORDATA cursorData
;
2393 TRACE("%p, %lu, %lu, %lu, %i, %i, %lu.\n", pbIconBits
, cbIconBits
, fIcon
, dwVersion
, cxDesired
, cyDesired
, uFlags
);
2395 if(uFlags
& LR_DEFAULTSIZE
)
2397 if(!cxDesired
) cxDesired
= GetSystemMetrics(fIcon
? SM_CXICON
: SM_CXCURSOR
);
2398 if(!cyDesired
) cyDesired
= GetSystemMetrics(fIcon
? SM_CYICON
: SM_CYCURSOR
);
2401 ZeroMemory(&cursorData
, sizeof(cursorData
));
2402 cursorData
.cx
= cxDesired
;
2403 cursorData
.cy
= cyDesired
;
2404 cursorData
.rt
= (USHORT
)((ULONG_PTR
)(fIcon
? RT_ICON
: RT_CURSOR
));
2406 /* Convert to win32k-ready data */
2407 if(!memcmp(pbIconBits
, "RIFF", 4))
2409 if(!CURSORICON_GetCursorDataFromANI(&cursorData
, pbIconBits
, cbIconBits
, uFlags
))
2411 ERR("Could not get cursor data from .ani.\n");
2414 isAnimated
= !!(cursorData
.CURSORF_flags
& CURSORF_ACON
);
2418 /* It is possible to pass Icon Directories to this API */
2419 int wResId
= LookupIconIdFromDirectoryEx(pbIconBits
, fIcon
, cxDesired
, cyDesired
, uFlags
);
2420 HANDLE ResHandle
= NULL
;
2425 CURSORICONDIR
* pCurIconDir
= (CURSORICONDIR
*)pbIconBits
;
2427 TRACE("Pointer points to a directory structure.\n");
2429 /* So this is a pointer to an icon directory structure. Find the module */
2430 if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
| GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
,
2431 (LPCWSTR
)pbIconBits
,
2437 /* Check we were given the right type of resource */
2438 if((fIcon
&& pCurIconDir
->idType
== 2) || (!fIcon
&& pCurIconDir
->idType
== 1))
2440 WARN("Got a %s directory pointer, but called for a %s", fIcon
? "cursor" : "icon", fIcon
? "icon" : "cursor");
2444 /* Get the relevant resource pointer */
2445 hrsrc
= FindResourceW(
2447 MAKEINTRESOURCEW(wResId
),
2448 fIcon
? RT_ICON
: RT_CURSOR
);
2452 ResHandle
= LoadResource(hinst
, hrsrc
);
2456 pbIconBits
= LockResource(ResHandle
);
2459 FreeResource(ResHandle
);
2465 WORD
* pt
= (WORD
*)pbIconBits
;
2466 cursorData
.xHotspot
= *pt
++;
2467 cursorData
.yHotspot
= *pt
++;
2468 pbIconBits
= (PBYTE
)pt
;
2471 if (!CURSORICON_GetCursorDataFromBMI(&cursorData
, (BITMAPINFO
*)pbIconBits
))
2473 ERR("Couldn't fill the CURSORDATA structure.\n");
2475 FreeResource(ResHandle
);
2479 FreeResource(ResHandle
);
2483 if (uFlags
& LR_SHARED
)
2484 cursorData
.CURSORF_flags
|= CURSORF_LRSHARED
;
2486 hIcon
= NtUserxCreateEmptyCurObject(isAnimated
);
2490 if(!NtUserSetCursorIconData(hIcon
, NULL
, NULL
, &cursorData
))
2492 ERR("NtUserSetCursorIconData failed.\n");
2493 NtUserDestroyCursor(hIcon
, TRUE
);
2498 HeapFree(GetProcessHeap(), 0, cursorData
.aspcur
);
2505 HeapFree(GetProcessHeap(), 0, cursorData
.aspcur
);
2506 DeleteObject(cursorData
.hbmMask
);
2507 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
2508 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
2513 HICON WINAPI
CreateIconIndirect(
2514 _In_ PICONINFO piconinfo
2517 /* As simple as creating a handle, and let win32k deal with the bitmaps */
2519 CURSORDATA cursorData
;
2521 TRACE("%p.\n", piconinfo
);
2523 ZeroMemory(&cursorData
, sizeof(cursorData
));
2525 if(!CURSORICON_GetCursorDataFromIconInfo(&cursorData
, piconinfo
))
2528 hiconRet
= NtUserxCreateEmptyCurObject(FALSE
);
2532 if(!NtUserSetCursorIconData(hiconRet
, NULL
, NULL
, &cursorData
))
2534 NtUserDestroyCursor(hiconRet
, FALSE
);
2538 TRACE("Returning 0x%08x.\n", hiconRet
);
2544 DeleteObject(cursorData
.hbmMask
);
2545 if(cursorData
.hbmColor
) DeleteObject(cursorData
.hbmColor
);
2546 if(cursorData
.hbmAlpha
) DeleteObject(cursorData
.hbmAlpha
);
2551 HCURSOR WINAPI
CreateCursor(
2552 _In_opt_ HINSTANCE hInst
,
2557 _In_
const VOID
*pvANDPlane
,
2558 _In_
const VOID
*pvXORPlane
2564 TRACE_(cursor
)("%dx%d spot=%d,%d xor=%p and=%p\n",
2565 nWidth
, nHeight
, xHotSpot
, yHotSpot
, pvXORPlane
, pvANDPlane
);
2568 info
.xHotspot
= xHotSpot
;
2569 info
.yHotspot
= yHotSpot
;
2570 info
.hbmMask
= CreateBitmap( nWidth
, nHeight
, 1, 1, pvANDPlane
);
2571 info
.hbmColor
= CreateBitmap( nWidth
, nHeight
, 1, 1, pvXORPlane
);
2572 hCursor
= CreateIconIndirect( &info
);
2573 DeleteObject( info
.hbmMask
);
2574 DeleteObject( info
.hbmColor
);
2578 BOOL WINAPI
SetSystemCursor(
2587 BOOL WINAPI
SetCursorPos(
2592 return NtUserxSetCursorPos(X
,Y
);
2595 BOOL WINAPI
GetCursorPos(
2596 _Out_ LPPOINT lpPoint
2599 return NtUserxGetCursorPos(lpPoint
);
2602 int WINAPI
ShowCursor(
2606 return NtUserxShowCursor(bShow
);
2609 HCURSOR WINAPI
GetCursor(void)
2611 return (HCURSOR
)NtUserGetThreadState(THREADSTATE_GETCURSOR
);
2614 BOOL WINAPI
DestroyCursor(
2615 _In_ HCURSOR hCursor
2618 return NtUserDestroyCursor(hCursor
, FALSE
);
2623 GetCursorFrameInfo(HCURSOR hCursor
, DWORD reserved
, DWORD istep
, PINT rate_jiffies
, DWORD
*num_steps
)
2625 return NtUserGetCursorFrameInfo(hCursor
, istep
, rate_jiffies
, num_steps
);