1c2c66affSColin Finck /*
2c2c66affSColin Finck  * PROJECT:         ReactOS user32.dll
3c2c66affSColin Finck  * COPYRIGHT:       GPL - See COPYING in the top level directory
4c2c66affSColin Finck  * FILE:            win32ss/user/user32/windows/cursoricon.c
5c2c66affSColin Finck  * PURPOSE:         cursor and icons implementation
6c2c66affSColin Finck  * PROGRAMMER:      Jérôme Gardou (jerome.gardou@reactos.org)
7c2c66affSColin Finck  */
8c2c66affSColin Finck 
9c2c66affSColin Finck #include <user32.h>
10c2c66affSColin Finck 
11c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL(cursor);
12c2c66affSColin Finck WINE_DECLARE_DEBUG_CHANNEL(icon);
13c2c66affSColin Finck //WINE_DECLARE_DEBUG_CHANNEL(resource);
14c2c66affSColin Finck 
15c2c66affSColin Finck /* We only use Wide string functions */
16c2c66affSColin Finck #undef MAKEINTRESOURCE
17c2c66affSColin Finck #define MAKEINTRESOURCE MAKEINTRESOURCEW
18c2c66affSColin Finck 
19c2c66affSColin Finck /************* USER32 INTERNAL FUNCTIONS **********/
20c2c66affSColin Finck 
LoadSystemCursors(VOID)21c2c66affSColin Finck VOID LoadSystemCursors(VOID)
22c2c66affSColin Finck {
23c2c66affSColin Finck    if (!gpsi->hIconSmWindows)
24c2c66affSColin Finck    {
25c2c66affSColin Finck        ERR("Loading System Cursors\n");
26c2c66affSColin Finck        NtUserSetSystemCursor(LoadImageW( 0, IDC_ARROW,       IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_NORMAL);
27c2c66affSColin Finck        NtUserSetSystemCursor(LoadImageW( 0, IDC_IBEAM,       IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_IBEAM);
28c2c66affSColin Finck        NtUserSetSystemCursor(LoadImageW( 0, IDC_WAIT,        IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_WAIT);
29c2c66affSColin Finck        NtUserSetSystemCursor(LoadImageW( 0, IDC_CROSS,       IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_CROSS);
30c2c66affSColin Finck        NtUserSetSystemCursor(LoadImageW( 0, IDC_UPARROW,     IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_UP);
31c2c66affSColin Finck        NtUserSetSystemCursor(LoadImageW( 0, IDC_ICON,        IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_ICON);
32c2c66affSColin Finck        NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZE,        IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_SIZE);
33c2c66affSColin Finck        NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZENWSE,    IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_SIZENWSE);
34c2c66affSColin Finck        NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZENESW,    IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_SIZENESW);
35c2c66affSColin Finck        NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZEWE,      IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_SIZEWE);
36c2c66affSColin Finck        NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZENS,      IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_SIZENS);
37c2c66affSColin Finck        NtUserSetSystemCursor(LoadImageW( 0, IDC_SIZEALL,     IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_SIZEALL);
38c2c66affSColin Finck        NtUserSetSystemCursor(LoadImageW( 0, IDC_NO,          IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_NO);
39c2c66affSColin Finck        NtUserSetSystemCursor(LoadImageW( 0, IDC_HAND,        IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_HAND);
40c2c66affSColin Finck        NtUserSetSystemCursor(LoadImageW( 0, IDC_APPSTARTING, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_APPSTARTING);
41c2c66affSColin Finck        NtUserSetSystemCursor(LoadImageW( 0, IDC_HELP,        IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ), OCR_HELP);
42c2c66affSColin Finck    }
43c2c66affSColin Finck }
44c2c66affSColin Finck 
45c2c66affSColin Finck /* This callback routine is called directly after switching to gui mode */
46c2c66affSColin Finck NTSTATUS
47c2c66affSColin Finck WINAPI
User32SetupDefaultCursors(PVOID Arguments,ULONG ArgumentLength)48c2c66affSColin Finck User32SetupDefaultCursors(PVOID Arguments,
49c2c66affSColin Finck                           ULONG ArgumentLength)
50c2c66affSColin Finck {
51c2c66affSColin Finck     BOOL *DefaultCursor = (BOOL*)Arguments;
52c2c66affSColin Finck     HCURSOR hCursor;
53c2c66affSColin Finck 
54c2c66affSColin Finck     /* Load system cursors first */
55c2c66affSColin Finck     LoadSystemCursors();
56c2c66affSColin Finck 
57c2c66affSColin Finck     if(*DefaultCursor)
58c2c66affSColin Finck     {
59c2c66affSColin Finck         /* set default cursor */
60c2c66affSColin Finck         hCursor = LoadCursorW(0, IDC_ARROW);
61c2c66affSColin Finck         SetCursor(hCursor);
62c2c66affSColin Finck     }
63c2c66affSColin Finck     else
64c2c66affSColin Finck     {
65c2c66affSColin Finck         /* FIXME load system cursor scheme */
66c2c66affSColin Finck         SetCursor(0);
67c2c66affSColin Finck         hCursor = LoadCursorW(0, IDC_ARROW);
68c2c66affSColin Finck         SetCursor(hCursor);
69c2c66affSColin Finck     }
70c2c66affSColin Finck 
71c2c66affSColin Finck     return(ZwCallbackReturn(&hCursor, sizeof(HCURSOR), STATUS_SUCCESS));
72c2c66affSColin Finck }
73c2c66affSColin Finck 
get_icon_size(HICON hIcon,SIZE * size)74c2c66affSColin Finck BOOL get_icon_size(HICON hIcon, SIZE *size)
75c2c66affSColin Finck {
76c2c66affSColin Finck     return NtUserGetIconSize(hIcon, 0, &size->cx, &size->cy);
77c2c66affSColin Finck }
78c2c66affSColin Finck 
CursorIconToCursor(HICON hIcon,BOOL SemiTransparent)79c2c66affSColin Finck HCURSOR CursorIconToCursor(HICON hIcon, BOOL SemiTransparent)
80c2c66affSColin Finck {
81c2c66affSColin Finck     UNIMPLEMENTED;
82c2c66affSColin Finck     return NULL;
83c2c66affSColin Finck }
84c2c66affSColin Finck 
85c2c66affSColin Finck /************* IMPLEMENTATION HELPERS ******************/
86c2c66affSColin Finck 
87c2c66affSColin Finck static const WCHAR DISPLAYW[] = L"DISPLAY";
88c2c66affSColin Finck 
map_fileW(LPCWSTR name,LPDWORD filesize)89c2c66affSColin Finck static void *map_fileW( LPCWSTR name, LPDWORD filesize )
90c2c66affSColin Finck {
91c2c66affSColin Finck     HANDLE hFile, hMapping;
92c2c66affSColin Finck     LPVOID ptr = NULL;
93c2c66affSColin Finck 
94c2c66affSColin Finck     hFile = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL,
95c2c66affSColin Finck                          OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0 );
96c2c66affSColin Finck     if (hFile != INVALID_HANDLE_VALUE)
97c2c66affSColin Finck     {
98c2c66affSColin Finck         hMapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
99c2c66affSColin Finck         if (hMapping)
100c2c66affSColin Finck         {
101c2c66affSColin Finck             ptr = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
102c2c66affSColin Finck             CloseHandle( hMapping );
103c2c66affSColin Finck             if (filesize)
104c2c66affSColin Finck                 *filesize = GetFileSize( hFile, NULL );
105c2c66affSColin Finck         }
106c2c66affSColin Finck         CloseHandle( hFile );
107c2c66affSColin Finck     }
108c2c66affSColin Finck     return ptr;
109c2c66affSColin Finck }
110c2c66affSColin Finck 
get_dib_image_size(int width,int height,int depth)111c2c66affSColin Finck static int get_dib_image_size( int width, int height, int depth )
112c2c66affSColin Finck {
113c2c66affSColin Finck     return (((width * depth + 31) / 8) & ~3) * abs( height );
114c2c66affSColin Finck }
115c2c66affSColin Finck 
is_dib_monochrome(const BITMAPINFO * info)116c2c66affSColin Finck static BOOL is_dib_monochrome( const BITMAPINFO* info )
117c2c66affSColin Finck {
118c2c66affSColin Finck     if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
119c2c66affSColin Finck     {
120c2c66affSColin Finck         const RGBTRIPLE *rgb = ((const BITMAPCOREINFO*)info)->bmciColors;
121c2c66affSColin Finck 
122c2c66affSColin Finck         if (((const BITMAPCOREINFO*)info)->bmciHeader.bcBitCount != 1) return FALSE;
123c2c66affSColin Finck 
124c2c66affSColin Finck         /* Check if the first color is black */
125c2c66affSColin Finck         if ((rgb->rgbtRed == 0) && (rgb->rgbtGreen == 0) && (rgb->rgbtBlue == 0))
126c2c66affSColin Finck         {
127c2c66affSColin Finck             rgb++;
128c2c66affSColin Finck 
129c2c66affSColin Finck             /* Check if the second color is white */
130c2c66affSColin Finck             return ((rgb->rgbtRed == 0xff) && (rgb->rgbtGreen == 0xff)
131c2c66affSColin Finck                  && (rgb->rgbtBlue == 0xff));
132c2c66affSColin Finck         }
133c2c66affSColin Finck         else return FALSE;
134c2c66affSColin Finck     }
135c2c66affSColin Finck     else  /* assume BITMAPINFOHEADER */
136c2c66affSColin Finck     {
137c2c66affSColin Finck         const RGBQUAD *rgb = info->bmiColors;
138c2c66affSColin Finck 
139c2c66affSColin Finck         if (info->bmiHeader.biBitCount != 1) return FALSE;
140c2c66affSColin Finck 
141c2c66affSColin Finck         /* Check if the first color is black */
142c2c66affSColin Finck         if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) &&
143c2c66affSColin Finck             (rgb->rgbBlue == 0) && (rgb->rgbReserved == 0))
144c2c66affSColin Finck         {
145c2c66affSColin Finck             rgb++;
146c2c66affSColin Finck 
147c2c66affSColin Finck             /* Check if the second color is white */
148c2c66affSColin Finck             return ((rgb->rgbRed == 0xff) && (rgb->rgbGreen == 0xff)
149c2c66affSColin Finck                  && (rgb->rgbBlue == 0xff) && (rgb->rgbReserved == 0));
150c2c66affSColin Finck         }
151c2c66affSColin Finck         else return FALSE;
152c2c66affSColin Finck     }
153c2c66affSColin Finck }
154c2c66affSColin Finck 
155116c0cd9SDoug Lyons /* Return the size of the bitmap info structure including color table and
156116c0cd9SDoug Lyons  * the bytes required for 3 DWORDS if this is a BI_BITFIELDS bmp. */
bitmap_info_size(const BITMAPINFO * info,WORD coloruse)157c2c66affSColin Finck static int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
158c2c66affSColin Finck {
159c2c66affSColin Finck     unsigned int colors, size, masks = 0;
160c2c66affSColin Finck 
161c2c66affSColin Finck     if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
162c2c66affSColin Finck     {
163c2c66affSColin Finck         const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
164c2c66affSColin Finck         colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
165c2c66affSColin Finck         return sizeof(BITMAPCOREHEADER) + colors *
166c2c66affSColin Finck              ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
167c2c66affSColin Finck     }
168c2c66affSColin Finck     else  /* assume BITMAPINFOHEADER */
169c2c66affSColin Finck     {
170c2c66affSColin Finck         colors = info->bmiHeader.biClrUsed;
171c2c66affSColin Finck         if (colors > 256) /* buffer overflow otherwise */
172c2c66affSColin Finck                 colors = 256;
173c2c66affSColin Finck         if (!colors && (info->bmiHeader.biBitCount <= 8))
174c2c66affSColin Finck             colors = 1 << info->bmiHeader.biBitCount;
175116c0cd9SDoug Lyons         /* Account for BI_BITFIELDS in BITMAPINFOHEADER(v1-v3) bmp's. The
176116c0cd9SDoug Lyons          * 'max' selection using biSize below will exclude v4 & v5's. */
177c2c66affSColin Finck         if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
178c2c66affSColin Finck         size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
179116c0cd9SDoug Lyons         /* Test for BI_BITFIELDS format and either 16 or 32 bpp.
180116c0cd9SDoug Lyons          * If so, account for the 3 DWORD masks (RGB Order).
181116c0cd9SDoug Lyons          * BITMAPCOREHEADER tested above has no 16 or 32 bpp types.
182116c0cd9SDoug Lyons          * See table "All of the possible pixel formats in a DIB"
183116c0cd9SDoug Lyons          * at https://en.wikipedia.org/wiki/BMP_file_format. */
184116c0cd9SDoug Lyons         if (info->bmiHeader.biSize >= sizeof(BITMAPV4HEADER) &&
185116c0cd9SDoug Lyons             info->bmiHeader.biCompression == BI_BITFIELDS &&
186116c0cd9SDoug Lyons             (info->bmiHeader.biBitCount == 16 || info->bmiHeader.biBitCount == 32))
187116c0cd9SDoug Lyons         {
188116c0cd9SDoug Lyons             size += 3 * sizeof(DWORD);  // BI_BITFIELDS
189116c0cd9SDoug Lyons         }
190c2c66affSColin Finck         return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
191c2c66affSColin Finck     }
192c2c66affSColin Finck }
193c2c66affSColin Finck 
DIB_GetBitmapInfo(const BITMAPINFOHEADER * header,LONG * width,LONG * height,WORD * bpp,DWORD * compr)194c2c66affSColin Finck static int DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width,
195c2c66affSColin Finck                               LONG *height, WORD *bpp, DWORD *compr )
196c2c66affSColin Finck {
197afd39cbcSDoug Lyons     #define CR 13
198afd39cbcSDoug Lyons     #define LF 10
199afd39cbcSDoug Lyons     #define EOFM 26 // DOS End Of File Marker
200afd39cbcSDoug Lyons     #define HighBitDetect 0x89 // Byte with high bit set to test if not 7-bit
201afd39cbcSDoug Lyons     /* wine's definition */
202afd39cbcSDoug Lyons     static const BYTE png_sig_pattern[] = { HighBitDetect, 'P', 'N', 'G', CR, LF, EOFM, LF };
203c2c66affSColin Finck     if (header->biSize == sizeof(BITMAPCOREHEADER))
204c2c66affSColin Finck     {
205c2c66affSColin Finck         const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header;
206c2c66affSColin Finck         *width  = core->bcWidth;
207c2c66affSColin Finck         *height = core->bcHeight;
208c2c66affSColin Finck         *bpp    = core->bcBitCount;
209c2c66affSColin Finck         *compr  = 0;
210c2c66affSColin Finck         return 0;
211c2c66affSColin Finck     }
212c2c66affSColin Finck     else if (header->biSize == sizeof(BITMAPINFOHEADER) ||
213c2c66affSColin Finck              header->biSize == sizeof(BITMAPV4HEADER) ||
214c2c66affSColin Finck              header->biSize == sizeof(BITMAPV5HEADER))
215c2c66affSColin Finck     {
216c2c66affSColin Finck         *width  = header->biWidth;
217c2c66affSColin Finck         *height = header->biHeight;
218c2c66affSColin Finck         *bpp    = header->biBitCount;
219c2c66affSColin Finck         *compr  = header->biCompression;
220c2c66affSColin Finck         return 1;
221c2c66affSColin Finck     }
222afd39cbcSDoug Lyons     if (memcmp(&header->biSize, png_sig_pattern, sizeof(png_sig_pattern)) == 0)
223afd39cbcSDoug Lyons     {
224afd39cbcSDoug Lyons         ERR("Cannot yet display PNG icons\n");
225afd39cbcSDoug Lyons         /* for PNG format details see https://en.wikipedia.org/wiki/PNG */
226afd39cbcSDoug Lyons     }
227afd39cbcSDoug Lyons     else
228afd39cbcSDoug Lyons     {
229afd39cbcSDoug Lyons         ERR("Unknown/wrong size for header of 0x%x\n", header->biSize );
230afd39cbcSDoug Lyons     }
231c2c66affSColin Finck     return -1;
232c2c66affSColin Finck }
233c2c66affSColin Finck 
234c2c66affSColin Finck /* copy an icon bitmap, even when it can't be selected into a DC */
235c2c66affSColin Finck /* helper for CreateIconIndirect */
stretch_blt_icon(HDC hdc_dst,int dst_width,int dst_height,HBITMAP src)236c2c66affSColin Finck static void stretch_blt_icon(HDC hdc_dst, int dst_width, int dst_height, HBITMAP src)
237c2c66affSColin Finck {
238c2c66affSColin Finck     HDC hdc = CreateCompatibleDC( 0 );
239c2c66affSColin Finck     BITMAP bm;
240c2c66affSColin Finck     HBITMAP hbmpPrev;
241c2c66affSColin Finck 
242c2c66affSColin Finck     GetObjectW(src, sizeof(bm), &bm);
243c2c66affSColin Finck 
244c2c66affSColin Finck     hbmpPrev = SelectObject(hdc, src);
245c2c66affSColin Finck 
246c2c66affSColin Finck     if (!hbmpPrev)  /* do it the hard way */
247c2c66affSColin Finck     {
248c2c66affSColin Finck         BITMAPINFO *info;
249c2c66affSColin Finck         void *bits;
250c2c66affSColin Finck 
251c2c66affSColin Finck         if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) return;
252c2c66affSColin Finck         info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
253c2c66affSColin Finck         info->bmiHeader.biWidth = bm.bmWidth;
254c2c66affSColin Finck         info->bmiHeader.biHeight = bm.bmHeight;
255c2c66affSColin Finck         info->bmiHeader.biPlanes = GetDeviceCaps( hdc_dst, PLANES );
256c2c66affSColin Finck         info->bmiHeader.biBitCount = GetDeviceCaps( hdc_dst, BITSPIXEL );
257c2c66affSColin Finck         info->bmiHeader.biCompression = BI_RGB;
258c2c66affSColin Finck         info->bmiHeader.biSizeImage = get_dib_image_size( bm.bmWidth, bm.bmHeight, info->bmiHeader.biBitCount );
259c2c66affSColin Finck         info->bmiHeader.biXPelsPerMeter = 0;
260c2c66affSColin Finck         info->bmiHeader.biYPelsPerMeter = 0;
261c2c66affSColin Finck         info->bmiHeader.biClrUsed = 0;
262c2c66affSColin Finck         info->bmiHeader.biClrImportant = 0;
263c2c66affSColin Finck         bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage );
264c2c66affSColin Finck         if (bits && GetDIBits( hdc, src, 0, bm.bmHeight, bits, info, DIB_RGB_COLORS ))
265c2c66affSColin Finck             StretchDIBits( hdc_dst, 0, 0, dst_width, dst_height,
266c2c66affSColin Finck                            0, 0, bm.bmWidth, bm.bmHeight, bits, info, DIB_RGB_COLORS, SRCCOPY );
267c2c66affSColin Finck 
268c2c66affSColin Finck         HeapFree( GetProcessHeap(), 0, bits );
269c2c66affSColin Finck         HeapFree( GetProcessHeap(), 0, info );
270c2c66affSColin Finck     }
271c2c66affSColin Finck     else
272c2c66affSColin Finck     {
273c2c66affSColin Finck         StretchBlt( hdc_dst, 0, 0, dst_width, dst_height, hdc, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY );
274c2c66affSColin Finck         SelectObject(hdc, hbmpPrev);
275c2c66affSColin Finck     }
276c2c66affSColin Finck 
277c2c66affSColin Finck     DeleteDC( hdc );
278c2c66affSColin Finck }
279c2c66affSColin Finck 
280c2c66affSColin Finck /***********************************************************************
281c2c66affSColin Finck  *          bmi_has_alpha
282c2c66affSColin Finck  */
bmi_has_alpha(const BITMAPINFO * info,const void * bits)283c2c66affSColin Finck static BOOL bmi_has_alpha( const BITMAPINFO *info, const void *bits )
284c2c66affSColin Finck {
285c2c66affSColin Finck     int i;
286c2c66affSColin Finck     BOOL has_alpha = FALSE;
287c2c66affSColin Finck     const unsigned char *ptr = bits;
288c2c66affSColin Finck 
289c2c66affSColin Finck     if (info->bmiHeader.biBitCount != 32) return FALSE;
290c2c66affSColin Finck     for (i = 0; i < info->bmiHeader.biWidth * abs(info->bmiHeader.biHeight); i++, ptr += 4)
291c2c66affSColin Finck         if ((has_alpha = (ptr[3] != 0))) break;
292c2c66affSColin Finck     return has_alpha;
293c2c66affSColin Finck }
294c2c66affSColin Finck 
295c2c66affSColin Finck /***********************************************************************
296c2c66affSColin Finck  *          create_alpha_bitmap
297c2c66affSColin Finck  *
298c2c66affSColin Finck  * Create the alpha bitmap for a 32-bpp icon that has an alpha channel.
299c2c66affSColin Finck  */
300c2c66affSColin Finck static
301c2c66affSColin Finck HBITMAP
create_alpha_bitmap(_In_opt_ HBITMAP color,_In_opt_ BITMAPINFO * src_info,_In_opt_ const void * color_bits,_In_ LONG width,_In_ LONG height)302c2c66affSColin Finck create_alpha_bitmap(
303c2c66affSColin Finck     _In_opt_  HBITMAP color,
304c2c66affSColin Finck     _In_opt_  BITMAPINFO *src_info,
305c2c66affSColin Finck     _In_opt_  const void *color_bits,
306c2c66affSColin Finck     _In_ LONG width,
307c2c66affSColin Finck     _In_ LONG height)
308c2c66affSColin Finck {
309c2c66affSColin Finck     HBITMAP alpha = NULL, hbmpOld;
310c2c66affSColin Finck     HDC hdc = NULL, hdcScreen;
311c2c66affSColin Finck     unsigned char *ptr;
312c2c66affSColin Finck     void *bits = NULL;
313e9ad66d5STimo Kreuzer     ULONG size;
314c2c66affSColin Finck 
315c2c66affSColin Finck     hdcScreen = CreateDCW(DISPLAYW, NULL, NULL, NULL);
316c2c66affSColin Finck     if (!hdcScreen)
317c2c66affSColin Finck         return NULL;
318c2c66affSColin Finck     hdc = CreateCompatibleDC(hdcScreen);
319c2c66affSColin Finck     if (!hdc)
320c2c66affSColin Finck     {
321c2c66affSColin Finck         DeleteDC(hdcScreen);
322c2c66affSColin Finck         return NULL;
323c2c66affSColin Finck     }
324c2c66affSColin Finck 
325c2c66affSColin Finck     if (color)
326c2c66affSColin Finck     {
327c2c66affSColin Finck         BITMAP bm;
328c2c66affSColin Finck         BITMAPINFO *info = NULL;
329c2c66affSColin Finck 
330c2c66affSColin Finck         TRACE("Creating alpha bitmap from existing bitmap.\n");
331c2c66affSColin Finck 
332c2c66affSColin Finck         if (!GetObjectW( color, sizeof(bm), &bm ))
333c2c66affSColin Finck             goto done;
334c2c66affSColin Finck         if (bm.bmBitsPixel != 32)
335c2c66affSColin Finck             goto done;
336c2c66affSColin Finck 
337c2c66affSColin Finck         size = get_dib_image_size(bm.bmWidth, bm.bmHeight, 32);
338c2c66affSColin Finck 
339c2c66affSColin Finck         info = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(BITMAPINFO, bmiColors[256]));
340c2c66affSColin Finck         if(!info)
341c2c66affSColin Finck             goto done;
342c2c66affSColin Finck         info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
343c2c66affSColin Finck         info->bmiHeader.biWidth = bm.bmWidth;
344c2c66affSColin Finck         info->bmiHeader.biHeight = -bm.bmHeight;
345c2c66affSColin Finck         info->bmiHeader.biPlanes = 1;
346c2c66affSColin Finck         info->bmiHeader.biBitCount = 32;
347c2c66affSColin Finck         info->bmiHeader.biCompression = BI_RGB;
348c2c66affSColin Finck         info->bmiHeader.biSizeImage = size;
349c2c66affSColin Finck         info->bmiHeader.biXPelsPerMeter = 0;
350c2c66affSColin Finck         info->bmiHeader.biYPelsPerMeter = 0;
351c2c66affSColin Finck         info->bmiHeader.biClrUsed = 0;
352c2c66affSColin Finck         info->bmiHeader.biClrImportant = 0;
353c2c66affSColin Finck 
354c2c66affSColin Finck         bits = HeapAlloc(GetProcessHeap(), 0, size);
355c2c66affSColin Finck         if(!bits)
356c2c66affSColin Finck         {
357c2c66affSColin Finck             HeapFree(GetProcessHeap(), 0, info);
358c2c66affSColin Finck             goto done;
359c2c66affSColin Finck         }
360c2c66affSColin Finck         if(!GetDIBits( hdc, color, 0, bm.bmHeight, bits, info, DIB_RGB_COLORS ))
361c2c66affSColin Finck         {
362c2c66affSColin Finck             HeapFree(GetProcessHeap(), 0, info);
363c2c66affSColin Finck             goto done;
364c2c66affSColin Finck         }
365c2c66affSColin Finck         if (!bmi_has_alpha( info, bits ))
366c2c66affSColin Finck         {
367c2c66affSColin Finck             HeapFree(GetProcessHeap(), 0, info);
368c2c66affSColin Finck             goto done;
369c2c66affSColin Finck         }
370c2c66affSColin Finck 
371c2c66affSColin Finck         /* pre-multiply by alpha */
372c2c66affSColin Finck         for (ptr = bits; ptr < ((BYTE*)bits + size); ptr += 4)
373c2c66affSColin Finck         {
374c2c66affSColin Finck             unsigned int alpha = ptr[3];
375c2c66affSColin Finck             ptr[0] = (ptr[0] * alpha) / 255;
376c2c66affSColin Finck             ptr[1] = (ptr[1] * alpha) / 255;
377c2c66affSColin Finck             ptr[2] = (ptr[2] * alpha) / 255;
378c2c66affSColin Finck         }
379c2c66affSColin Finck 
380c2c66affSColin Finck         /* Directly create a 32-bits DDB (thanks to undocumented CreateDIBitmap flag). */
381c2c66affSColin Finck         alpha = CreateDIBitmap(hdc, NULL, CBM_INIT | 2, bits, info, DIB_RGB_COLORS);
382c2c66affSColin Finck 
383c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, info);
384c2c66affSColin Finck     }
385c2c66affSColin Finck     else
386c2c66affSColin Finck     {
387c2c66affSColin Finck         WORD bpp;
388c2c66affSColin Finck         DWORD compr;
389c2c66affSColin Finck         LONG orig_width, orig_height;
390c2c66affSColin Finck 
391c2c66affSColin Finck         TRACE("Creating alpha bitmap from bitmap info.\n");
392c2c66affSColin Finck 
393c2c66affSColin Finck         if(!bmi_has_alpha(src_info, color_bits))
394c2c66affSColin Finck             goto done;
395c2c66affSColin Finck 
396c2c66affSColin Finck         if(!DIB_GetBitmapInfo(&src_info->bmiHeader, &orig_width, &orig_height, &bpp, &compr))
397c2c66affSColin Finck             goto done;
398c2c66affSColin Finck         if(bpp != 32)
399c2c66affSColin Finck             goto done;
400c2c66affSColin Finck 
401c2c66affSColin Finck         size = get_dib_image_size(orig_width, orig_height, bpp);
402c2c66affSColin Finck         bits = HeapAlloc(GetProcessHeap(), 0, size);
403c2c66affSColin Finck         if(!bits)
404c2c66affSColin Finck             goto done;
405c2c66affSColin Finck         CopyMemory(bits, color_bits, size);
406c2c66affSColin Finck         /* pre-multiply by alpha */
407c2c66affSColin Finck         for (ptr = bits; ptr < ((BYTE*)bits + size); ptr += 4)
408c2c66affSColin Finck         {
409c2c66affSColin Finck             unsigned int alpha = ptr[3];
410c2c66affSColin Finck             ptr[0] = (ptr[0] * alpha) / 255;
411c2c66affSColin Finck             ptr[1] = (ptr[1] * alpha) / 255;
412c2c66affSColin Finck             ptr[2] = (ptr[2] * alpha) / 255;
413c2c66affSColin Finck         }
414c2c66affSColin Finck 
415c2c66affSColin Finck         /* Create the bitmap. Set the bitmap info to have the right width and height */
416c2c66affSColin Finck         if(src_info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
417c2c66affSColin Finck         {
418c2c66affSColin Finck             ((BITMAPCOREHEADER*)&src_info->bmiHeader)->bcWidth = width;
419c2c66affSColin Finck             ((BITMAPCOREHEADER*)&src_info->bmiHeader)->bcHeight = height;
420c2c66affSColin Finck         }
421c2c66affSColin Finck         else
422c2c66affSColin Finck         {
423c2c66affSColin Finck             src_info->bmiHeader.biWidth = width;
424c2c66affSColin Finck             src_info->bmiHeader.biHeight = height;
425c2c66affSColin Finck         }
426c2c66affSColin Finck         /* Directly create a 32-bits DDB (thanks to undocumented CreateDIBitmap flag). */
427c2c66affSColin Finck         alpha = CreateDIBitmap(hdcScreen, NULL, 2, NULL, src_info, DIB_RGB_COLORS);
428c2c66affSColin Finck         /* Restore values */
429c2c66affSColin Finck         if(src_info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
430c2c66affSColin Finck         {
431c2c66affSColin Finck             ((BITMAPCOREHEADER*)&src_info->bmiHeader)->bcWidth = orig_width;
432c2c66affSColin Finck             ((BITMAPCOREHEADER*)&src_info->bmiHeader)->bcHeight = orig_height;
433c2c66affSColin Finck         }
434c2c66affSColin Finck         else
435c2c66affSColin Finck         {
436c2c66affSColin Finck             src_info->bmiHeader.biWidth = orig_width;
437c2c66affSColin Finck             src_info->bmiHeader.biHeight = orig_height;
438c2c66affSColin Finck         }
439c2c66affSColin Finck         if(!alpha)
440c2c66affSColin Finck             goto done;
441c2c66affSColin Finck         hbmpOld = SelectObject(hdc, alpha);
442c2c66affSColin Finck         if(!hbmpOld)
443c2c66affSColin Finck         {
444c2c66affSColin Finck             DeleteObject(alpha);
445c2c66affSColin Finck             alpha = NULL;
446c2c66affSColin Finck             goto done;
447c2c66affSColin Finck         }
448c2c66affSColin Finck         if(!StretchDIBits( hdc, 0, 0, width, height,
449c2c66affSColin Finck                    0, 0, orig_width, orig_height,
450c2c66affSColin Finck                    bits, src_info, DIB_RGB_COLORS, SRCCOPY ))
451c2c66affSColin Finck         {
452c2c66affSColin Finck             SelectObject(hdc, hbmpOld);
453c2c66affSColin Finck             hbmpOld = NULL;
454c2c66affSColin Finck             DeleteObject(alpha);
455c2c66affSColin Finck             alpha = NULL;
456c2c66affSColin Finck         }
457c2c66affSColin Finck         else
458c2c66affSColin Finck         {
459c2c66affSColin Finck             SelectObject(hdc, hbmpOld);
460c2c66affSColin Finck         }
461c2c66affSColin Finck     }
462c2c66affSColin Finck 
463c2c66affSColin Finck done:
464c2c66affSColin Finck     DeleteDC(hdcScreen);
465c2c66affSColin Finck     DeleteDC( hdc );
466c2c66affSColin Finck     if(bits) HeapFree(GetProcessHeap(), 0, bits);
467c2c66affSColin Finck 
468c2c66affSColin Finck     TRACE("Returning 0x%08x.\n", alpha);
469c2c66affSColin Finck     return alpha;
470c2c66affSColin Finck }
471c2c66affSColin Finck 
472c2c66affSColin Finck #include "pshpack1.h"
473c2c66affSColin Finck 
474c2c66affSColin Finck typedef struct {
475c2c66affSColin Finck     BYTE bWidth;
476c2c66affSColin Finck     BYTE bHeight;
477c2c66affSColin Finck     BYTE bColorCount;
478c2c66affSColin Finck     BYTE bReserved;
479c2c66affSColin Finck     WORD xHotspot;
480c2c66affSColin Finck     WORD yHotspot;
481c2c66affSColin Finck     DWORD dwDIBSize;
482c2c66affSColin Finck     DWORD dwDIBOffset;
483c2c66affSColin Finck } CURSORICONFILEDIRENTRY;
484c2c66affSColin Finck 
485c2c66affSColin Finck typedef struct
486c2c66affSColin Finck {
487c2c66affSColin Finck     WORD                idReserved;
488c2c66affSColin Finck     WORD                idType;
489c2c66affSColin Finck     WORD                idCount;
490c2c66affSColin Finck     CURSORICONFILEDIRENTRY  idEntries[1];
491c2c66affSColin Finck } CURSORICONFILEDIR;
492c2c66affSColin Finck 
493c2c66affSColin Finck #include "poppack.h"
494c2c66affSColin Finck 
495c2c66affSColin Finck const CURSORICONFILEDIRENTRY*
get_best_icon_file_entry(_In_ const CURSORICONFILEDIR * dir,_In_ DWORD dwFileSize,_In_ int cxDesired,_In_ int cyDesired,_In_ BOOL bIcon,_In_ DWORD fuLoad)496c2c66affSColin Finck get_best_icon_file_entry(
497c2c66affSColin Finck     _In_ const CURSORICONFILEDIR* dir,
498c2c66affSColin Finck     _In_ DWORD dwFileSize,
499c2c66affSColin Finck     _In_ int cxDesired,
500c2c66affSColin Finck     _In_ int cyDesired,
501c2c66affSColin Finck     _In_ BOOL bIcon,
502c2c66affSColin Finck     _In_ DWORD fuLoad
503c2c66affSColin Finck )
504c2c66affSColin Finck {
505c2c66affSColin Finck     CURSORICONDIR* fakeDir;
506c2c66affSColin Finck     CURSORICONDIRENTRY* fakeEntry;
507c2c66affSColin Finck     WORD i;
508c2c66affSColin Finck     const CURSORICONFILEDIRENTRY* entry;
509c2c66affSColin Finck 
510c2c66affSColin Finck     /* Check our file is what it claims to be */
511c2c66affSColin Finck     if ( dwFileSize < sizeof(*dir) )
512c2c66affSColin Finck         return NULL;
513c2c66affSColin Finck 
514c2c66affSColin Finck     if (dwFileSize < FIELD_OFFSET(CURSORICONFILEDIR, idEntries[dir->idCount]))
515c2c66affSColin Finck         return NULL;
516c2c66affSColin Finck 
517c2c66affSColin Finck     /*
518c2c66affSColin Finck      * Cute little hack:
519c2c66affSColin Finck      * We allocate a buffer, fake it as if it was a pointer to a resource in a module,
520c2c66affSColin Finck      * pass it to LookupIconIdFromDirectoryEx and get back the index we have to use
521c2c66affSColin Finck      */
522c2c66affSColin Finck     fakeDir = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(CURSORICONDIR, idEntries[dir->idCount]));
523c2c66affSColin Finck     if(!fakeDir)
524c2c66affSColin Finck     {
525c2c66affSColin Finck         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
526c2c66affSColin Finck         return NULL;
527c2c66affSColin Finck     }
528c2c66affSColin Finck     fakeDir->idReserved = 0;
529c2c66affSColin Finck     fakeDir->idType = dir->idType;
530c2c66affSColin Finck     fakeDir->idCount = dir->idCount;
531c2c66affSColin Finck     for(i = 0; i<dir->idCount; i++)
532c2c66affSColin Finck     {
533c2c66affSColin Finck         fakeEntry = &fakeDir->idEntries[i];
534c2c66affSColin Finck         entry = &dir->idEntries[i];
535c2c66affSColin Finck         /* Take this as an occasion to perform a size check */
536c2c66affSColin Finck         if ((entry->dwDIBOffset > dwFileSize)
537c2c66affSColin Finck                 || ((entry->dwDIBOffset + entry->dwDIBSize) > dwFileSize))
538c2c66affSColin Finck         {
539c2c66affSColin Finck             ERR("Corrupted icon file?.\n");
540c2c66affSColin Finck             HeapFree(GetProcessHeap(), 0, fakeDir);
541c2c66affSColin Finck             return NULL;
542c2c66affSColin Finck         }
543c2c66affSColin Finck         /* File icon/cursors are not like resource ones */
544c2c66affSColin Finck         if(bIcon)
545c2c66affSColin Finck         {
546c2c66affSColin Finck             fakeEntry->ResInfo.icon.bWidth = entry->bWidth;
547c2c66affSColin Finck             fakeEntry->ResInfo.icon.bHeight = entry->bHeight;
548c2c66affSColin Finck             fakeEntry->ResInfo.icon.bColorCount = 0;
549c2c66affSColin Finck             fakeEntry->ResInfo.icon.bReserved = 0;
550c2c66affSColin Finck         }
551c2c66affSColin Finck         else
552c2c66affSColin Finck         {
553c2c66affSColin Finck             fakeEntry->ResInfo.cursor.wWidth = entry->bWidth;
554c2c66affSColin Finck             fakeEntry->ResInfo.cursor.wHeight = entry->bHeight;
555c2c66affSColin Finck         }
556c2c66affSColin Finck         /* Let's assume there's always one plane */
557c2c66affSColin Finck         fakeEntry->wPlanes = 1;
558c2c66affSColin Finck         /* We must get the bitcount from the BITMAPINFOHEADER itself */
559c2c66affSColin Finck         if (((BITMAPINFOHEADER *)((char *)dir + entry->dwDIBOffset))->biSize == sizeof(BITMAPCOREHEADER))
560c2c66affSColin Finck             fakeEntry->wBitCount = ((BITMAPCOREHEADER *)((char *)dir + entry->dwDIBOffset))->bcBitCount;
561c2c66affSColin Finck         else
562c2c66affSColin Finck             fakeEntry->wBitCount = ((BITMAPINFOHEADER *)((char *)dir + entry->dwDIBOffset))->biBitCount;
563c2c66affSColin Finck         fakeEntry->dwBytesInRes = entry->dwDIBSize;
564c2c66affSColin Finck         fakeEntry->wResId = i + 1;
565c2c66affSColin Finck     }
566c2c66affSColin Finck 
567c2c66affSColin Finck     /* Now call LookupIconIdFromResourceEx */
568c2c66affSColin Finck     i = LookupIconIdFromDirectoryEx((PBYTE)fakeDir, bIcon, cxDesired, cyDesired, fuLoad & LR_MONOCHROME);
569c2c66affSColin Finck     /* We don't need this anymore */
570c2c66affSColin Finck     HeapFree(GetProcessHeap(), 0, fakeDir);
571c2c66affSColin Finck     if(i == 0)
572c2c66affSColin Finck     {
573c2c66affSColin Finck         WARN("Unable to get a fit entry index.\n");
574c2c66affSColin Finck         return NULL;
575c2c66affSColin Finck     }
576c2c66affSColin Finck 
577c2c66affSColin Finck     /* We found it */
578c2c66affSColin Finck     return &dir->idEntries[i-1];
579c2c66affSColin Finck }
580c2c66affSColin Finck 
581c2c66affSColin Finck DWORD
get_best_icon_file_offset(_In_ const LPBYTE dir,_In_ DWORD dwFileSize,_In_ int cxDesired,_In_ int cyDesired,_In_ BOOL bIcon,_In_ DWORD fuLoad,_Out_ POINT * ptHotSpot)582c2c66affSColin Finck get_best_icon_file_offset(
583c2c66affSColin Finck     _In_ const LPBYTE dir,
584c2c66affSColin Finck     _In_ DWORD dwFileSize,
585c2c66affSColin Finck     _In_ int cxDesired,
586c2c66affSColin Finck     _In_ int cyDesired,
587c2c66affSColin Finck     _In_ BOOL bIcon,
588c2c66affSColin Finck     _In_ DWORD fuLoad,
589c2c66affSColin Finck     _Out_ POINT *ptHotSpot
590c2c66affSColin Finck )
591c2c66affSColin Finck {
592c2c66affSColin Finck     const CURSORICONFILEDIRENTRY *entry;
593c2c66affSColin Finck 
594c2c66affSColin Finck     entry = get_best_icon_file_entry((CURSORICONFILEDIR *) dir, dwFileSize, cxDesired, cyDesired, bIcon, fuLoad);
595c2c66affSColin Finck 
596c2c66affSColin Finck     if(ptHotSpot)
597c2c66affSColin Finck     {
598c2c66affSColin Finck         ptHotSpot->x = entry->xHotspot;
599c2c66affSColin Finck         ptHotSpot->y = entry->yHotspot;
600c2c66affSColin Finck     }
601c2c66affSColin Finck 
602c2c66affSColin Finck     if(entry)
603c2c66affSColin Finck         return entry->dwDIBOffset;
604c2c66affSColin Finck 
605c2c66affSColin Finck     return 0;
606c2c66affSColin Finck }
607c2c66affSColin Finck 
608c2c66affSColin Finck 
609c2c66affSColin Finck 
610c2c66affSColin Finck /************* IMPLEMENTATION CORE ****************/
611c2c66affSColin Finck 
CURSORICON_GetCursorDataFromBMI(_Inout_ CURSORDATA * pdata,_In_ const BITMAPINFO * pbmi)612c2c66affSColin Finck static BOOL CURSORICON_GetCursorDataFromBMI(
613c2c66affSColin Finck     _Inout_ CURSORDATA* pdata,
614c2c66affSColin Finck     _In_    const BITMAPINFO *pbmi
615c2c66affSColin Finck )
616c2c66affSColin Finck {
617c2c66affSColin Finck     UINT ubmiSize = bitmap_info_size(pbmi, DIB_RGB_COLORS);
618c2c66affSColin Finck     BOOL monochrome = is_dib_monochrome(pbmi);
619c2c66affSColin Finck     LONG width, height;
620c2c66affSColin Finck     WORD bpp;
621c2c66affSColin Finck     DWORD compr;
622c2c66affSColin Finck     int ibmpType;
623c2c66affSColin Finck     HDC hdc, hdcScreen;
624c2c66affSColin Finck     BITMAPINFO* pbmiCopy;
625c2c66affSColin Finck     HBITMAP hbmpOld = NULL;
626c2c66affSColin Finck     BOOL bResult = FALSE;
627c2c66affSColin Finck     const VOID *pvColor, *pvMask;
628c2c66affSColin Finck 
629c2c66affSColin Finck     ibmpType = DIB_GetBitmapInfo(&pbmi->bmiHeader, &width, &height, &bpp, &compr);
630c2c66affSColin Finck     /* Invalid data */
631c2c66affSColin Finck     if(ibmpType < 0)
632c2c66affSColin Finck         return FALSE;
633c2c66affSColin Finck 
634c2c66affSColin Finck     /* No compression for icons */
635c2c66affSColin Finck     if(compr != BI_RGB)
636c2c66affSColin Finck         return FALSE;
637c2c66affSColin Finck 
638c2c66affSColin Finck     /* If no dimensions were set, use the one from the icon */
639c2c66affSColin Finck     if(!pdata->cx) pdata->cx = width;
640c2c66affSColin Finck     if(!pdata->cy) pdata->cy = height < 0 ? -height/2 : height/2;
641c2c66affSColin Finck 
642c2c66affSColin Finck     /* Fix the hotspot coords */
643c2c66affSColin Finck     if(pdata->rt == (USHORT)((ULONG_PTR)RT_CURSOR))
644c2c66affSColin Finck     {
645c2c66affSColin Finck         if(pdata->cx != width)
646c2c66affSColin Finck             pdata->xHotspot = (pdata->xHotspot * pdata->cx) / width;
647c2c66affSColin Finck         if(pdata->cy != height/2)
648c2c66affSColin Finck             pdata->yHotspot = (pdata->yHotspot * pdata->cy * 2) / height;
649c2c66affSColin Finck     }
650c2c66affSColin Finck     else
651c2c66affSColin Finck     {
652c2c66affSColin Finck         pdata->xHotspot = pdata->cx/2;
653c2c66affSColin Finck         pdata->yHotspot = pdata->cy/2;
654c2c66affSColin Finck     }
655c2c66affSColin Finck 
656c2c66affSColin Finck     hdcScreen = CreateDCW(DISPLAYW, NULL, NULL, NULL);
657c2c66affSColin Finck     if(!hdcScreen)
658c2c66affSColin Finck         return FALSE;
659c2c66affSColin Finck     hdc = CreateCompatibleDC(hdcScreen);
660c2c66affSColin Finck     if(!hdc)
661c2c66affSColin Finck     {
662c2c66affSColin Finck         DeleteDC(hdcScreen);
663c2c66affSColin Finck         return FALSE;
664c2c66affSColin Finck     }
665c2c66affSColin Finck 
666c2c66affSColin Finck     pbmiCopy = HeapAlloc(GetProcessHeap(), 0, max(ubmiSize, FIELD_OFFSET(BITMAPINFO, bmiColors[3])));
667c2c66affSColin Finck     if(!pbmiCopy)
668c2c66affSColin Finck         goto done;
669c2c66affSColin Finck     RtlCopyMemory(pbmiCopy, pbmi, ubmiSize);
670c2c66affSColin Finck 
671c2c66affSColin Finck     /* In an icon/cursor, the BITMAPINFO holds twice the height */
672c2c66affSColin Finck     if(pbmiCopy->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
673c2c66affSColin Finck         ((BITMAPCOREHEADER*)&pbmiCopy->bmiHeader)->bcHeight /= 2;
674c2c66affSColin Finck     else
675c2c66affSColin Finck         pbmiCopy->bmiHeader.biHeight /= 2;
676c2c66affSColin Finck     height /= 2;
677c2c66affSColin Finck 
678c2c66affSColin Finck     pvColor = (const char*)pbmi + ubmiSize;
679c2c66affSColin Finck     pvMask = (const char*)pvColor +
680c2c66affSColin Finck         get_dib_image_size(width, height, bpp );
681c2c66affSColin Finck 
682c2c66affSColin Finck     /* Set XOR bits */
683c2c66affSColin Finck     if(monochrome)
684c2c66affSColin Finck     {
685c2c66affSColin Finck         /* Create the 1bpp bitmap which will contain everything */
686c2c66affSColin Finck         pdata->hbmColor = NULL;
687c2c66affSColin Finck         pdata->hbmMask = CreateBitmap(pdata->cx, pdata->cy * 2, 1, 1, NULL);
688c2c66affSColin Finck         if(!pdata->hbmMask)
689c2c66affSColin Finck             goto done;
690c2c66affSColin Finck         hbmpOld = SelectObject(hdc, pdata->hbmMask);
691c2c66affSColin Finck         if(!hbmpOld)
692c2c66affSColin Finck             goto done;
693c2c66affSColin Finck 
694c2c66affSColin Finck         if(!StretchDIBits(hdc, 0, pdata->cy, pdata->cx, pdata->cy,
695c2c66affSColin Finck                           0, 0, width, height,
696c2c66affSColin Finck                           pvColor, pbmiCopy, DIB_RGB_COLORS, SRCCOPY))
697c2c66affSColin Finck             goto done;
698c2c66affSColin Finck         pdata->bpp = 1;
699c2c66affSColin Finck     }
700c2c66affSColin Finck     else
701c2c66affSColin Finck     {
702c2c66affSColin Finck         /* Create the bitmap. It has to be compatible with the screen surface */
703c2c66affSColin Finck         pdata->hbmColor = CreateCompatibleBitmap(hdcScreen, pdata->cx, pdata->cy);
704c2c66affSColin Finck         if(!pdata->hbmColor)
705c2c66affSColin Finck             goto done;
706c2c66affSColin Finck         /* Create the 1bpp mask bitmap */
707c2c66affSColin Finck         pdata->hbmMask = CreateBitmap(pdata->cx, pdata->cy, 1, 1, NULL);
708c2c66affSColin Finck         if(!pdata->hbmMask)
709c2c66affSColin Finck             goto done;
710c2c66affSColin Finck         hbmpOld = SelectObject(hdc, pdata->hbmColor);
711c2c66affSColin Finck         if(!hbmpOld)
712c2c66affSColin Finck             goto done;
713c2c66affSColin Finck         if(!StretchDIBits(hdc, 0, 0, pdata->cx, pdata->cy,
714c2c66affSColin Finck                   0, 0, width, height,
715c2c66affSColin Finck                   pvColor, pbmiCopy, DIB_RGB_COLORS, SRCCOPY))
716c2c66affSColin Finck             goto done;
717c2c66affSColin Finck         pdata->bpp = GetDeviceCaps(hdcScreen, BITSPIXEL);
718c2c66affSColin Finck         pdata->hbmAlpha = create_alpha_bitmap(NULL, pbmiCopy, pvColor, pdata->cx, pdata->cy);
719c2c66affSColin Finck 
720c2c66affSColin Finck         /* Now convert the info to monochrome for the mask bits */
721c2c66affSColin Finck         if (pbmiCopy->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
722c2c66affSColin Finck         {
723c2c66affSColin Finck             RGBQUAD *rgb = pbmiCopy->bmiColors;
724c2c66affSColin Finck 
725c2c66affSColin Finck             pbmiCopy->bmiHeader.biClrUsed = pbmiCopy->bmiHeader.biClrImportant = 2;
726c2c66affSColin Finck             rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
727c2c66affSColin Finck             rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
728c2c66affSColin Finck             rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
729c2c66affSColin Finck             pbmiCopy->bmiHeader.biBitCount = 1;
730c2c66affSColin Finck         }
731c2c66affSColin Finck         else
732c2c66affSColin Finck         {
733c2c66affSColin Finck             RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pbmiCopy) + 1);
734c2c66affSColin Finck 
735c2c66affSColin Finck             rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
736c2c66affSColin Finck             rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
737c2c66affSColin Finck             ((BITMAPCOREHEADER*)&pbmiCopy->bmiHeader)->bcBitCount = 1;
738c2c66affSColin Finck         }
739c2c66affSColin Finck     }
740c2c66affSColin Finck     /* Set the mask bits */
741c2c66affSColin Finck     if(!SelectObject(hdc, pdata->hbmMask))
742c2c66affSColin Finck         goto done;
743c2c66affSColin Finck     bResult = StretchDIBits(hdc, 0, 0, pdata->cx, pdata->cy,
744c2c66affSColin Finck                   0, 0, width, height,
745c2c66affSColin Finck                   pvMask, pbmiCopy, DIB_RGB_COLORS, SRCCOPY) != 0;
746c2c66affSColin Finck 
747c2c66affSColin Finck done:
748c2c66affSColin Finck     DeleteDC(hdcScreen);
749c2c66affSColin Finck     if(hbmpOld) SelectObject(hdc, hbmpOld);
750c2c66affSColin Finck     DeleteDC(hdc);
751c2c66affSColin Finck     if(pbmiCopy) HeapFree(GetProcessHeap(), 0, pbmiCopy);
752c2c66affSColin Finck     /* Clean up in case of failure */
753c2c66affSColin Finck     if(!bResult)
754c2c66affSColin Finck     {
755c2c66affSColin Finck         if(pdata->hbmMask) DeleteObject(pdata->hbmMask);
756c2c66affSColin Finck         if(pdata->hbmColor) DeleteObject(pdata->hbmColor);
757c2c66affSColin Finck         if(pdata->hbmAlpha) DeleteObject(pdata->hbmAlpha);
758c2c66affSColin Finck     }
759c2c66affSColin Finck     return bResult;
760c2c66affSColin Finck }
761c2c66affSColin Finck 
CURSORICON_GetCursorDataFromIconInfo(_Out_ CURSORDATA * pCursorData,_In_ ICONINFO * pIconInfo)762c2c66affSColin Finck static BOOL CURSORICON_GetCursorDataFromIconInfo(
763c2c66affSColin Finck   _Out_ CURSORDATA* pCursorData,
764c2c66affSColin Finck   _In_  ICONINFO* pIconInfo
765c2c66affSColin Finck )
766c2c66affSColin Finck {
767c2c66affSColin Finck     BITMAP bm;
768c2c66affSColin Finck 
769c2c66affSColin Finck     ZeroMemory(pCursorData, sizeof(*pCursorData));
770c2c66affSColin Finck     if(pIconInfo->hbmColor)
771c2c66affSColin Finck     {
772c2c66affSColin Finck         /* We must convert the color bitmap to screen format */
773c2c66affSColin Finck         HDC hdcScreen, hdcMem;
774c2c66affSColin Finck         HBITMAP hbmpPrev;
775c2c66affSColin Finck 
776c2c66affSColin Finck         /* The mask dictates its dimensions */
777c2c66affSColin Finck         if (!GetObject(pIconInfo->hbmMask, sizeof(bm), &bm))
778c2c66affSColin Finck             return FALSE;
779c2c66affSColin Finck         hdcScreen = CreateDCW(DISPLAYW, NULL, NULL, NULL);
780c2c66affSColin Finck         if(!hdcScreen)
781c2c66affSColin Finck             return FALSE;
782c2c66affSColin Finck         hdcMem = CreateCompatibleDC(hdcScreen);
783c2c66affSColin Finck         if(!hdcMem)
784c2c66affSColin Finck         {
785c2c66affSColin Finck             DeleteDC(hdcScreen);
786c2c66affSColin Finck             return FALSE;
787c2c66affSColin Finck         }
788c2c66affSColin Finck         pCursorData->hbmColor = CreateCompatibleBitmap(hdcScreen, bm.bmWidth, bm.bmHeight);
789c2c66affSColin Finck         DeleteDC(hdcScreen);
790c2c66affSColin Finck         if (!pCursorData->hbmColor)
791c2c66affSColin Finck         {
792c2c66affSColin Finck             DeleteDC(hdcMem);
793c2c66affSColin Finck             return FALSE;
794c2c66affSColin Finck         }
795c2c66affSColin Finck         hbmpPrev = SelectObject(hdcMem, pCursorData->hbmColor);
796c2c66affSColin Finck         if (!hbmpPrev)
797c2c66affSColin Finck         {
798c2c66affSColin Finck             DeleteDC(hdcMem);
799c2c66affSColin Finck             DeleteObject(pCursorData->hbmColor);
800c2c66affSColin Finck             return FALSE;
801c2c66affSColin Finck         }
802c2c66affSColin Finck         stretch_blt_icon( hdcMem, bm.bmWidth, bm.bmHeight, pIconInfo->hbmColor);
803c2c66affSColin Finck         SelectObject(hdcMem, hbmpPrev);
804c2c66affSColin Finck         DeleteDC(hdcMem);
805c2c66affSColin Finck     }
806c2c66affSColin Finck     pCursorData->hbmMask = CopyImage(pIconInfo->hbmMask, IMAGE_BITMAP, 0, 0, LR_MONOCHROME);
807c2c66affSColin Finck     if(!pCursorData->hbmMask)
808c2c66affSColin Finck         return FALSE;
809c2c66affSColin Finck 
810c2c66affSColin Finck     /* Now, fill some information */
811c2c66affSColin Finck     pCursorData->rt = (USHORT)((ULONG_PTR)(pIconInfo->fIcon ? RT_ICON : RT_CURSOR));
812c2c66affSColin Finck     if(pCursorData->hbmColor)
813c2c66affSColin Finck     {
814c2c66affSColin Finck         GetObject(pCursorData->hbmColor, sizeof(bm), &bm);
815c2c66affSColin Finck         pCursorData->bpp = bm.bmBitsPixel;
816c2c66affSColin Finck         pCursorData->cx = bm.bmWidth;
817c2c66affSColin Finck         pCursorData->cy = bm.bmHeight;
818c2c66affSColin Finck         if(pCursorData->bpp == 32)
819c2c66affSColin Finck             pCursorData->hbmAlpha = create_alpha_bitmap(pCursorData->hbmColor, NULL, NULL, 0, 0);
820c2c66affSColin Finck     }
821c2c66affSColin Finck     else
822c2c66affSColin Finck     {
823c2c66affSColin Finck         GetObject(pCursorData->hbmMask, sizeof(bm), &bm);
824c2c66affSColin Finck         pCursorData->bpp = 1;
825c2c66affSColin Finck         pCursorData->cx = bm.bmWidth;
826c2c66affSColin Finck         pCursorData->cy = bm.bmHeight/2;
827c2c66affSColin Finck     }
828c2c66affSColin Finck 
829c2c66affSColin Finck     if(pIconInfo->fIcon)
830c2c66affSColin Finck     {
831c2c66affSColin Finck         pCursorData->xHotspot = pCursorData->cx/2;
832c2c66affSColin Finck         pCursorData->yHotspot = pCursorData->cy/2;
833c2c66affSColin Finck     }
834c2c66affSColin Finck     else
835c2c66affSColin Finck     {
836c2c66affSColin Finck         pCursorData->xHotspot = pIconInfo->xHotspot;
837c2c66affSColin Finck         pCursorData->yHotspot = pIconInfo->yHotspot;
838c2c66affSColin Finck     }
839c2c66affSColin Finck 
840c2c66affSColin Finck     return TRUE;
841c2c66affSColin Finck }
842c2c66affSColin Finck 
843c2c66affSColin Finck 
844c2c66affSColin Finck #define RIFF_FOURCC( c0, c1, c2, c3 ) \
845c2c66affSColin Finck         ( (DWORD)(BYTE)(c0) | ( (DWORD)(BYTE)(c1) << 8 ) | \
846c2c66affSColin Finck         ( (DWORD)(BYTE)(c2) << 16 ) | ( (DWORD)(BYTE)(c3) << 24 ) )
847c2c66affSColin Finck 
848c2c66affSColin Finck #define ANI_RIFF_ID RIFF_FOURCC('R', 'I', 'F', 'F')
849c2c66affSColin Finck #define ANI_LIST_ID RIFF_FOURCC('L', 'I', 'S', 'T')
850c2c66affSColin Finck #define ANI_ACON_ID RIFF_FOURCC('A', 'C', 'O', 'N')
851c2c66affSColin Finck #define ANI_anih_ID RIFF_FOURCC('a', 'n', 'i', 'h')
852c2c66affSColin Finck #define ANI_seq__ID RIFF_FOURCC('s', 'e', 'q', ' ')
853c2c66affSColin Finck #define ANI_fram_ID RIFF_FOURCC('f', 'r', 'a', 'm')
854c2c66affSColin Finck #define ANI_rate_ID RIFF_FOURCC('r', 'a', 't', 'e')
855c2c66affSColin Finck 
856c2c66affSColin Finck #define ANI_FLAG_ICON       0x1
857c2c66affSColin Finck #define ANI_FLAG_SEQUENCE   0x2
858c2c66affSColin Finck 
859c2c66affSColin Finck #include <pshpack1.h>
860c2c66affSColin Finck typedef struct {
861c2c66affSColin Finck     DWORD header_size;
862c2c66affSColin Finck     DWORD num_frames;
863c2c66affSColin Finck     DWORD num_steps;
864c2c66affSColin Finck     DWORD width;
865c2c66affSColin Finck     DWORD height;
866c2c66affSColin Finck     DWORD bpp;
867c2c66affSColin Finck     DWORD num_planes;
868c2c66affSColin Finck     DWORD display_rate;
869c2c66affSColin Finck     DWORD flags;
870c2c66affSColin Finck } ani_header;
871c2c66affSColin Finck 
872c2c66affSColin Finck typedef struct {
873c2c66affSColin Finck     DWORD           data_size;
874c2c66affSColin Finck     const unsigned char   *data;
875c2c66affSColin Finck } riff_chunk_t;
876c2c66affSColin Finck #include <poppack.h>
877c2c66affSColin Finck 
dump_ani_header(const ani_header * header)878c2c66affSColin Finck static void dump_ani_header( const ani_header *header )
879c2c66affSColin Finck {
880c2c66affSColin Finck     TRACE("     header size: %d\n", header->header_size);
881c2c66affSColin Finck     TRACE("          frames: %d\n", header->num_frames);
882c2c66affSColin Finck     TRACE("           steps: %d\n", header->num_steps);
883c2c66affSColin Finck     TRACE("           width: %d\n", header->width);
884c2c66affSColin Finck     TRACE("          height: %d\n", header->height);
885c2c66affSColin Finck     TRACE("             bpp: %d\n", header->bpp);
886c2c66affSColin Finck     TRACE("          planes: %d\n", header->num_planes);
887c2c66affSColin Finck     TRACE("    display rate: %d\n", header->display_rate);
888c2c66affSColin Finck     TRACE("           flags: 0x%08x\n", header->flags);
889c2c66affSColin Finck }
890c2c66affSColin Finck 
891c2c66affSColin Finck /* Find an animated cursor chunk, given its type and ID */
riff_find_chunk(DWORD chunk_id,DWORD chunk_type,const riff_chunk_t * parent_chunk,riff_chunk_t * chunk)892c2c66affSColin Finck static void riff_find_chunk( DWORD chunk_id, DWORD chunk_type, const riff_chunk_t *parent_chunk, riff_chunk_t *chunk )
893c2c66affSColin Finck {
894c2c66affSColin Finck     const unsigned char *ptr = parent_chunk->data;
895c2c66affSColin Finck     const unsigned char *end = parent_chunk->data + (parent_chunk->data_size - (2 * sizeof(DWORD)));
896c2c66affSColin Finck 
897c2c66affSColin Finck     if (chunk_type == ANI_LIST_ID || chunk_type == ANI_RIFF_ID) end -= sizeof(DWORD);
898c2c66affSColin Finck 
899c2c66affSColin Finck     while (ptr < end)
900c2c66affSColin Finck     {
901c2c66affSColin Finck         if ((!chunk_type && *(const DWORD *)ptr == chunk_id )
902c2c66affSColin Finck                 || (chunk_type && *(const DWORD *)ptr == chunk_type && *((const DWORD *)ptr + 2) == chunk_id ))
903c2c66affSColin Finck         {
904c2c66affSColin Finck             ptr += sizeof(DWORD);
905c2c66affSColin Finck             chunk->data_size = (*(const DWORD *)ptr + 1) & ~1;
906c2c66affSColin Finck             ptr += sizeof(DWORD);
907c2c66affSColin Finck             if (chunk_type == ANI_LIST_ID || chunk_type == ANI_RIFF_ID) ptr += sizeof(DWORD);
908c2c66affSColin Finck             chunk->data = ptr;
909c2c66affSColin Finck 
910c2c66affSColin Finck             return;
911c2c66affSColin Finck         }
912c2c66affSColin Finck 
913c2c66affSColin Finck         ptr += sizeof(DWORD);
914c2c66affSColin Finck         ptr += (*(const DWORD *)ptr + 1) & ~1;
915c2c66affSColin Finck         ptr += sizeof(DWORD);
916c2c66affSColin Finck     }
917c2c66affSColin Finck }
918c2c66affSColin Finck 
CURSORICON_GetCursorDataFromANI(_Inout_ CURSORDATA * pCurData,_In_ const BYTE * pData,_In_ DWORD dwDataSize,_In_ DWORD fuLoad)919c2c66affSColin Finck static BOOL CURSORICON_GetCursorDataFromANI(
920c2c66affSColin Finck     _Inout_ CURSORDATA* pCurData,
921c2c66affSColin Finck     _In_    const BYTE *pData,
922c2c66affSColin Finck     _In_    DWORD dwDataSize,
923c2c66affSColin Finck     _In_    DWORD fuLoad
924c2c66affSColin Finck )
925c2c66affSColin Finck {
926c2c66affSColin Finck     UINT i;
927c2c66affSColin Finck     const ani_header *pHeader;
928c2c66affSColin Finck     riff_chunk_t root_chunk = { dwDataSize, pData };
929c2c66affSColin Finck     riff_chunk_t ACON_chunk = {0};
930c2c66affSColin Finck     riff_chunk_t anih_chunk = {0};
931c2c66affSColin Finck     riff_chunk_t fram_chunk = {0};
932c2c66affSColin Finck     riff_chunk_t rate_chunk = {0};
933c2c66affSColin Finck     riff_chunk_t seq_chunk = {0};
934c2c66affSColin Finck     const unsigned char *icon_chunk;
935c2c66affSColin Finck     const unsigned char *icon_data;
936c2c66affSColin Finck 
937c2c66affSColin Finck     /* Find the root chunk */
938c2c66affSColin Finck     riff_find_chunk( ANI_ACON_ID, ANI_RIFF_ID, &root_chunk, &ACON_chunk );
939c2c66affSColin Finck     if (!ACON_chunk.data)
940c2c66affSColin Finck     {
941c2c66affSColin Finck         ERR("Failed to get root chunk.\n");
942c2c66affSColin Finck         return FALSE;
943c2c66affSColin Finck     }
944c2c66affSColin Finck 
945c2c66affSColin Finck     /* Find the header chunk */
946c2c66affSColin Finck     riff_find_chunk( ANI_anih_ID, 0, &ACON_chunk, &anih_chunk );
947c2c66affSColin Finck     if (!ACON_chunk.data)
948c2c66affSColin Finck     {
949c2c66affSColin Finck         ERR("Failed to get header chunk.\n");
950c2c66affSColin Finck         return FALSE;
951c2c66affSColin Finck     }
952c2c66affSColin Finck     pHeader = (ani_header*)anih_chunk.data;
953c2c66affSColin Finck     dump_ani_header(pHeader);
954c2c66affSColin Finck 
955c2c66affSColin Finck     /* Set up the master data */
956c2c66affSColin Finck     pCurData->CURSORF_flags |= CURSORF_ACON;
957c2c66affSColin Finck     pCurData->cpcur = pHeader->num_frames;
958c2c66affSColin Finck     pCurData->cicur = pHeader->num_steps;
959c2c66affSColin Finck     pCurData->iicur = pHeader->display_rate;
960c2c66affSColin Finck 
961c2c66affSColin Finck     /* Get the sequences */
962c2c66affSColin Finck     if (pHeader->flags & ANI_FLAG_SEQUENCE)
963c2c66affSColin Finck     {
964c2c66affSColin Finck         riff_find_chunk( ANI_seq__ID, 0, &ACON_chunk, &seq_chunk );
965c2c66affSColin Finck         if (!seq_chunk.data)
966c2c66affSColin Finck         {
967c2c66affSColin Finck             ERR("No sequence data although the flag is set!\n");
968c2c66affSColin Finck             return FALSE;
969c2c66affSColin Finck         }
970c2c66affSColin Finck     }
971c2c66affSColin Finck 
972c2c66affSColin Finck     /* Get the frame rates */
973c2c66affSColin Finck     riff_find_chunk( ANI_rate_ID, 0, &ACON_chunk, &rate_chunk );
974c2c66affSColin Finck     if (rate_chunk.data)
975c2c66affSColin Finck         pCurData->ajifRate = (INT*)rate_chunk.data;
976c2c66affSColin Finck 
977c2c66affSColin Finck     /* Get the frames chunk */
978c2c66affSColin Finck     riff_find_chunk( ANI_fram_ID, ANI_LIST_ID, &ACON_chunk, &fram_chunk );
979c2c66affSColin Finck     if (!fram_chunk.data)
980c2c66affSColin Finck     {
981c2c66affSColin Finck         ERR("Failed to get icon list.\n");
982c2c66affSColin Finck         return 0;
983c2c66affSColin Finck     }
984c2c66affSColin Finck     icon_chunk = fram_chunk.data;
985c2c66affSColin Finck     icon_data = fram_chunk.data + (2 * sizeof(DWORD));
986c2c66affSColin Finck 
987c2c66affSColin Finck     if(pHeader->num_frames > 1)
988c2c66affSColin Finck     {
989c2c66affSColin Finck         /* Allocate frame descriptors, step indices and rates */
990c2c66affSColin Finck         pCurData->aspcur = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
991c2c66affSColin Finck             pHeader->num_frames * sizeof(CURSORDATA) + pHeader->num_steps * (sizeof(DWORD) + sizeof(INT)));
992c2c66affSColin Finck         if(!pCurData->aspcur)
993c2c66affSColin Finck         {
994c2c66affSColin Finck             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
995c2c66affSColin Finck             return FALSE;
996c2c66affSColin Finck         }
997c2c66affSColin Finck         pCurData->aicur = (DWORD*)(pCurData->aspcur + pHeader->num_frames);
998c2c66affSColin Finck         pCurData->ajifRate = (INT*)(pCurData->aicur + pHeader->num_steps);
999c2c66affSColin Finck     }
1000c2c66affSColin Finck 
1001c2c66affSColin Finck     for(i=0; i < pHeader->num_frames; i++)
1002c2c66affSColin Finck     {
1003c2c66affSColin Finck         CURSORDATA* pFrameData;
1004c2c66affSColin Finck         const DWORD chunk_size = *(const DWORD *)(icon_chunk + sizeof(DWORD));
1005c2c66affSColin Finck         const BITMAPINFO* pbmi;
1006c2c66affSColin Finck 
1007c2c66affSColin Finck         if(pHeader->num_frames > 1)
1008c2c66affSColin Finck             pFrameData = &pCurData->aspcur[i];
1009c2c66affSColin Finck         else
1010c2c66affSColin Finck             pFrameData = pCurData;
1011c2c66affSColin Finck 
1012c2c66affSColin Finck         pFrameData->rt = pCurData->rt;
1013c2c66affSColin Finck 
1014c2c66affSColin Finck         if (pHeader->flags & ANI_FLAG_ICON)
1015c2c66affSColin Finck         {
1016c2c66affSColin Finck             /* The chunks describe an icon file */
1017c2c66affSColin Finck             const CURSORICONFILEDIRENTRY* pDirEntry = get_best_icon_file_entry(
1018c2c66affSColin Finck                 (const CURSORICONFILEDIR *) icon_data,
1019c2c66affSColin Finck                 chunk_size,
1020c2c66affSColin Finck                 pCurData->cx,
1021c2c66affSColin Finck                 pCurData->cy,
1022c2c66affSColin Finck                 TRUE,
1023c2c66affSColin Finck                 fuLoad);
1024c2c66affSColin Finck             if(!pDirEntry)
1025c2c66affSColin Finck             {
1026c2c66affSColin Finck                 ERR("Unable to find the right file entry for frame %d.\n", i);
1027c2c66affSColin Finck                 goto error;
1028c2c66affSColin Finck             }
1029c2c66affSColin Finck             pFrameData->xHotspot = pDirEntry->xHotspot;
1030c2c66affSColin Finck             pFrameData->yHotspot = pDirEntry->yHotspot;
1031c2c66affSColin Finck             if(!pHeader->width || !pHeader->height)
1032c2c66affSColin Finck             {
1033c2c66affSColin Finck                 pFrameData->cx = pDirEntry->bWidth;
1034c2c66affSColin Finck                 pFrameData->cy = pDirEntry->bHeight;
1035c2c66affSColin Finck             }
1036c2c66affSColin Finck             else
1037c2c66affSColin Finck             {
1038c2c66affSColin Finck                 pFrameData->cx = pHeader->width;
1039c2c66affSColin Finck                 pFrameData->cy = pHeader->height;
1040c2c66affSColin Finck             }
1041c2c66affSColin Finck             pbmi = (const BITMAPINFO *) (icon_data + pDirEntry->dwDIBOffset);
1042c2c66affSColin Finck         }
1043c2c66affSColin Finck         else
1044c2c66affSColin Finck         {
1045c2c66affSColin Finck             /* The chunks just describe bitmaps */
1046c2c66affSColin Finck             pbmi = (const BITMAPINFO *)icon_data;
1047c2c66affSColin Finck             pFrameData->xHotspot = pFrameData->yHotspot = 0;
1048c2c66affSColin Finck         }
1049c2c66affSColin Finck 
1050c2c66affSColin Finck         /* Do the real work */
1051c2c66affSColin Finck         CURSORICON_GetCursorDataFromBMI(pFrameData, pbmi);
1052c2c66affSColin Finck 
1053c2c66affSColin Finck         if(pHeader->num_frames > 1)
1054c2c66affSColin Finck             pFrameData->CURSORF_flags |= CURSORF_ACONFRAME;
1055c2c66affSColin Finck         else
1056c2c66affSColin Finck             pFrameData->CURSORF_flags &= ~CURSORF_ACON;
1057c2c66affSColin Finck 
1058c2c66affSColin Finck 
1059c2c66affSColin Finck         /* Next frame */
1060c2c66affSColin Finck         icon_chunk += chunk_size + (2 * sizeof(DWORD));
1061c2c66affSColin Finck         icon_data = icon_chunk + (2 * sizeof(DWORD));
1062c2c66affSColin Finck     }
1063c2c66affSColin Finck 
1064c2c66affSColin Finck     if(pHeader->num_frames <= 1)
1065c2c66affSColin Finck         return TRUE;
1066c2c66affSColin Finck 
1067c2c66affSColin Finck     if(rate_chunk.data)
1068c2c66affSColin Finck         CopyMemory(pCurData->ajifRate, rate_chunk.data, pHeader->num_steps * sizeof(INT));
1069c2c66affSColin Finck     else
1070c2c66affSColin Finck     {
1071c2c66affSColin Finck         for(i=0; i < pHeader->num_steps; i++)
1072c2c66affSColin Finck             pCurData->ajifRate[i] = pHeader->display_rate;
1073c2c66affSColin Finck     }
1074c2c66affSColin Finck 
1075c2c66affSColin Finck     if (pHeader->flags & ANI_FLAG_SEQUENCE)
1076c2c66affSColin Finck     {
1077c2c66affSColin Finck         CopyMemory(pCurData->aicur, seq_chunk.data, pHeader->num_steps * sizeof(DWORD));
1078c2c66affSColin Finck     }
1079c2c66affSColin Finck     else
1080c2c66affSColin Finck     {
1081c2c66affSColin Finck         for(i=0; i < pHeader->num_steps; i++)
1082c2c66affSColin Finck             pCurData->aicur[i] = i;
1083c2c66affSColin Finck     }
1084c2c66affSColin Finck 
1085c2c66affSColin Finck     return TRUE;
1086c2c66affSColin Finck 
1087c2c66affSColin Finck error:
1088c2c66affSColin Finck     HeapFree(GetProcessHeap(), 0, pCurData->aspcur);
1089c2c66affSColin Finck     ZeroMemory(pCurData, sizeof(CURSORDATA));
1090c2c66affSColin Finck     return FALSE;
1091c2c66affSColin Finck }
1092c2c66affSColin Finck 
1093c2c66affSColin Finck 
1094c2c66affSColin Finck static
1095c2c66affSColin Finck HBITMAP
BITMAP_LoadImageW(_In_opt_ HINSTANCE hinst,_In_ LPCWSTR lpszName,_In_ int cxDesired,_In_ int cyDesired,_In_ UINT fuLoad)1096c2c66affSColin Finck BITMAP_LoadImageW(
1097c2c66affSColin Finck   _In_opt_  HINSTANCE hinst,
1098c2c66affSColin Finck   _In_      LPCWSTR lpszName,
1099c2c66affSColin Finck   _In_      int cxDesired,
1100c2c66affSColin Finck   _In_      int cyDesired,
1101c2c66affSColin Finck   _In_      UINT fuLoad
1102c2c66affSColin Finck )
1103c2c66affSColin Finck {
1104c2c66affSColin Finck     const BITMAPINFO* pbmi;
1105c2c66affSColin Finck     BITMAPINFO* pbmiScaled = NULL;
1106c2c66affSColin Finck     BITMAPINFO* pbmiCopy = NULL;
1107c2c66affSColin Finck     const VOID* pvMapping = NULL;
1108c2c66affSColin Finck     DWORD dwOffset = 0;
1109c2c66affSColin Finck     HGLOBAL hgRsrc = NULL;
1110c2c66affSColin Finck     int iBMISize;
1111c2c66affSColin Finck     PVOID pvBits;
1112c2c66affSColin Finck     HDC hdcScreen = NULL;
1113c2c66affSColin Finck     HDC hdc = NULL;
1114c2c66affSColin Finck     HBITMAP hbmpOld, hbmpRet = NULL;
1115c2c66affSColin Finck     LONG width, height;
1116c2c66affSColin Finck     WORD bpp;
1117116c0cd9SDoug Lyons     DWORD compr, ResSize = 0;
1118c2c66affSColin Finck 
1119c2c66affSColin Finck     /* Map the bitmap info */
1120c2c66affSColin Finck     if(fuLoad & LR_LOADFROMFILE)
1121c2c66affSColin Finck     {
1122c2c66affSColin Finck         const BITMAPFILEHEADER* pbmfh;
1123c2c66affSColin Finck 
1124c2c66affSColin Finck         pvMapping = map_fileW(lpszName, NULL);
1125c2c66affSColin Finck         if(!pvMapping)
1126c2c66affSColin Finck             return NULL;
1127c2c66affSColin Finck         pbmfh = pvMapping;
1128c2c66affSColin Finck         if (pbmfh->bfType != 0x4d42 /* 'BM' */)
1129c2c66affSColin Finck         {
1130c2c66affSColin Finck             WARN("Invalid/unsupported bitmap format!\n");
1131c2c66affSColin Finck             goto end;
1132c2c66affSColin Finck         }
1133c2c66affSColin Finck         pbmi = (const BITMAPINFO*)(pbmfh + 1);
1134c2c66affSColin Finck 
1135c2c66affSColin Finck         /* Get the image bits */
1136c2c66affSColin Finck         if(pbmfh->bfOffBits)
1137c2c66affSColin Finck             dwOffset = pbmfh->bfOffBits - sizeof(BITMAPFILEHEADER);
1138c2c66affSColin Finck     }
1139c2c66affSColin Finck     else
1140c2c66affSColin Finck     {
1141c2c66affSColin Finck         HRSRC hrsrc;
1142c2c66affSColin Finck 
1143c2c66affSColin Finck         /* Caller wants an OEM bitmap */
1144c2c66affSColin Finck         if(!hinst)
1145c2c66affSColin Finck             hinst = User32Instance;
1146c2c66affSColin Finck         hrsrc = FindResourceW(hinst, lpszName, RT_BITMAP);
1147c2c66affSColin Finck         if(!hrsrc)
1148c2c66affSColin Finck             return NULL;
1149c2c66affSColin Finck         hgRsrc = LoadResource(hinst, hrsrc);
1150c2c66affSColin Finck         if(!hgRsrc)
1151c2c66affSColin Finck             return NULL;
1152c2c66affSColin Finck         pbmi = LockResource(hgRsrc);
1153c2c66affSColin Finck         if(!pbmi)
1154c2c66affSColin Finck             return NULL;
1155116c0cd9SDoug Lyons         ResSize = SizeofResource(hinst, hrsrc);
1156c2c66affSColin Finck     }
1157c2c66affSColin Finck 
1158c2c66affSColin Finck     /* Fix up values */
1159c2c66affSColin Finck     if(DIB_GetBitmapInfo(&pbmi->bmiHeader, &width, &height, &bpp, &compr) == -1)
1160c2c66affSColin Finck         goto end;
1161c2c66affSColin Finck     if((width > 65535) || (height > 65535))
1162c2c66affSColin Finck         goto end;
1163c2c66affSColin Finck     if(cxDesired == 0)
1164c2c66affSColin Finck         cxDesired = width;
1165c2c66affSColin Finck     if(cyDesired == 0)
1166c2c66affSColin Finck         cyDesired = height;
1167c2c66affSColin Finck     else if(height < 0)
1168c2c66affSColin Finck         cyDesired = -cyDesired;
1169c2c66affSColin Finck 
1170c2c66affSColin Finck     iBMISize = bitmap_info_size(pbmi, DIB_RGB_COLORS);
1171c2c66affSColin Finck 
1172c2c66affSColin Finck     /* Get a pointer to the image data */
1173c2c66affSColin Finck     pvBits = (char*)pbmi + (dwOffset ? dwOffset : iBMISize);
1174c2c66affSColin Finck 
1175c2c66affSColin Finck     /* Create a copy of the info describing the bitmap in the file */
1176c2c66affSColin Finck     pbmiCopy = HeapAlloc(GetProcessHeap(), 0, iBMISize);
1177c2c66affSColin Finck     if(!pbmiCopy)
1178c2c66affSColin Finck         goto end;
1179c2c66affSColin Finck     CopyMemory(pbmiCopy, pbmi, iBMISize);
1180c2c66affSColin Finck 
1181116c0cd9SDoug Lyons     TRACE("Size Image %d, Size Header %d, ResSize %d\n",
1182116c0cd9SDoug Lyons         pbmiCopy->bmiHeader.biSizeImage, pbmiCopy->bmiHeader.biSize, ResSize);
1183116c0cd9SDoug Lyons 
1184116c0cd9SDoug Lyons     /* HACK: If this is a binutils' windres.exe compiled 16 or 32 bpp bitmap
1185116c0cd9SDoug Lyons      * using BI_BITFIELDS, then a bug causes it to fail to include
1186116c0cd9SDoug Lyons      * the bytes for the bitfields. So, we have to substract out the
1187116c0cd9SDoug Lyons      * size of the bitfields previously included from bitmap_info_size. */
1188116c0cd9SDoug Lyons     if (compr == BI_BITFIELDS && (bpp == 16 || bpp == 32) &&
1189116c0cd9SDoug Lyons         pbmiCopy->bmiHeader.biSizeImage + pbmiCopy->bmiHeader.biSize == ResSize)
1190116c0cd9SDoug Lyons     {
1191116c0cd9SDoug Lyons         /* GCC pointer to the image data has 12 less bytes than MSVC */
1192116c0cd9SDoug Lyons         pvBits = (char*)pvBits - 12;
1193116c0cd9SDoug Lyons         WARN("Found GCC Resource Compiled 16-bpp or 32-bpp error\n");
1194116c0cd9SDoug Lyons     }
1195116c0cd9SDoug Lyons 
1196c2c66affSColin Finck     /* Fix it up, if needed */
1197c2c66affSColin Finck     if(fuLoad & (LR_LOADTRANSPARENT | LR_LOADMAP3DCOLORS))
1198c2c66affSColin Finck     {
1199c2c66affSColin Finck         WORD bpp, incr, numColors;
1200c2c66affSColin Finck         char* pbmiColors;
1201c2c66affSColin Finck         RGBTRIPLE* ptr;
1202c2c66affSColin Finck         COLORREF crWindow, cr3DShadow, cr3DFace, cr3DLight;
1203c2c66affSColin Finck         BYTE pixel = *((BYTE*)pvBits);
1204c2c66affSColin Finck         UINT i;
1205c2c66affSColin Finck 
1206c2c66affSColin Finck         if(pbmiCopy->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1207c2c66affSColin Finck         {
1208c2c66affSColin Finck             bpp = ((BITMAPCOREHEADER*)&pbmiCopy->bmiHeader)->bcBitCount;
1209c2c66affSColin Finck             numColors = 1 << bpp;
1210c2c66affSColin Finck             /* BITMAPCOREINFO holds RGBTRIPLEs */
1211c2c66affSColin Finck             incr = 3;
1212c2c66affSColin Finck         }
1213c2c66affSColin Finck         else
1214c2c66affSColin Finck         {
1215c2c66affSColin Finck             bpp = pbmiCopy->bmiHeader.biBitCount;
1216c2c66affSColin Finck             /* BITMAPINFOHEADER holds RGBQUADs */
1217c2c66affSColin Finck             incr = 4;
1218c2c66affSColin Finck             numColors = pbmiCopy->bmiHeader.biClrUsed;
1219c2c66affSColin Finck             if(numColors > 256) numColors = 256;
1220c2c66affSColin Finck             if (!numColors && (bpp <= 8)) numColors = 1 << bpp;
1221c2c66affSColin Finck         }
1222c2c66affSColin Finck 
1223c2c66affSColin Finck         if(bpp > 8)
1224c2c66affSColin Finck             goto create_bitmap;
1225c2c66affSColin Finck 
1226c2c66affSColin Finck         pbmiColors = (char*)pbmiCopy + pbmiCopy->bmiHeader.biSize;
1227c2c66affSColin Finck 
1228c2c66affSColin Finck         /* Get the relevant colors */
1229c2c66affSColin Finck         crWindow = GetSysColor(COLOR_WINDOW);
1230c2c66affSColin Finck         cr3DShadow = GetSysColor(COLOR_3DSHADOW);
1231c2c66affSColin Finck         cr3DFace = GetSysColor(COLOR_3DFACE);
1232c2c66affSColin Finck         cr3DLight = GetSysColor(COLOR_3DLIGHT);
1233c2c66affSColin Finck 
1234c2c66affSColin Finck         /* Fix the transparent palette entry */
1235c2c66affSColin Finck         if(fuLoad & LR_LOADTRANSPARENT)
1236c2c66affSColin Finck         {
1237c2c66affSColin Finck             switch(bpp)
1238c2c66affSColin Finck             {
1239c2c66affSColin Finck                 case 1: pixel >>= 7; break;
1240c2c66affSColin Finck                 case 4: pixel >>= 4; break;
1241c2c66affSColin Finck                 case 8: break;
1242c2c66affSColin Finck                 default:
1243c2c66affSColin Finck                     FIXME("Unhandled bit depth %d.\n", bpp);
1244c2c66affSColin Finck                     goto create_bitmap;
1245c2c66affSColin Finck             }
1246c2c66affSColin Finck 
1247c2c66affSColin Finck             if(pixel >= numColors)
1248c2c66affSColin Finck             {
1249c2c66affSColin Finck                 ERR("Wrong pixel passed in.\n");
1250c2c66affSColin Finck                 goto create_bitmap;
1251c2c66affSColin Finck             }
1252c2c66affSColin Finck 
1253c2c66affSColin Finck             /* If both flags are set, we must use COLOR_3DFACE */
1254c2c66affSColin Finck             if(fuLoad & LR_LOADMAP3DCOLORS) crWindow = cr3DFace;
1255c2c66affSColin Finck 
1256c2c66affSColin Finck             /* Define the color */
1257c2c66affSColin Finck             ptr = (RGBTRIPLE*)(pbmiColors + pixel*incr);
1258c2c66affSColin Finck             ptr->rgbtBlue = GetBValue(crWindow);
1259c2c66affSColin Finck             ptr->rgbtGreen = GetGValue(crWindow);
1260c2c66affSColin Finck             ptr->rgbtRed = GetRValue(crWindow);
1261c2c66affSColin Finck             goto create_bitmap;
1262c2c66affSColin Finck         }
1263c2c66affSColin Finck 
1264c2c66affSColin Finck         /* If we are here, then LR_LOADMAP3DCOLORS is set without LR_TRANSPARENT */
1265c2c66affSColin Finck         for(i = 0; i<numColors; i++)
1266c2c66affSColin Finck         {
1267c2c66affSColin Finck             ptr = (RGBTRIPLE*)(pbmiColors + i*incr);
1268c2c66affSColin Finck             if((ptr->rgbtBlue == ptr->rgbtRed) && (ptr->rgbtBlue == ptr->rgbtGreen))
1269c2c66affSColin Finck             {
1270c2c66affSColin Finck                 if(ptr->rgbtBlue == 128)
1271c2c66affSColin Finck                 {
1272c2c66affSColin Finck                     ptr->rgbtBlue = GetBValue(cr3DShadow);
1273c2c66affSColin Finck                     ptr->rgbtGreen = GetGValue(cr3DShadow);
1274c2c66affSColin Finck                     ptr->rgbtRed = GetRValue(cr3DShadow);
1275c2c66affSColin Finck                 }
1276c2c66affSColin Finck                 if(ptr->rgbtBlue == 192)
1277c2c66affSColin Finck                 {
1278c2c66affSColin Finck                     ptr->rgbtBlue = GetBValue(cr3DFace);
1279c2c66affSColin Finck                     ptr->rgbtGreen = GetGValue(cr3DFace);
1280c2c66affSColin Finck                     ptr->rgbtRed = GetRValue(cr3DFace);
1281c2c66affSColin Finck                 }
1282c2c66affSColin Finck                 if(ptr->rgbtBlue == 223)
1283c2c66affSColin Finck                 {
1284c2c66affSColin Finck                     ptr->rgbtBlue = GetBValue(cr3DLight);
1285c2c66affSColin Finck                     ptr->rgbtGreen = GetGValue(cr3DLight);
1286c2c66affSColin Finck                     ptr->rgbtRed = GetRValue(cr3DLight);
1287c2c66affSColin Finck                 }
1288c2c66affSColin Finck             }
1289c2c66affSColin Finck         }
1290c2c66affSColin Finck     }
1291c2c66affSColin Finck 
1292c2c66affSColin Finck create_bitmap:
1293c2c66affSColin Finck     if(fuLoad & LR_CREATEDIBSECTION)
1294c2c66affSColin Finck     {
1295c2c66affSColin Finck         /* Allocate the BMI describing the new bitmap */
1296c2c66affSColin Finck         pbmiScaled = HeapAlloc(GetProcessHeap(), 0, iBMISize);
1297c2c66affSColin Finck         if(!pbmiScaled)
1298c2c66affSColin Finck             goto end;
1299c2c66affSColin Finck         CopyMemory(pbmiScaled, pbmiCopy, iBMISize);
1300c2c66affSColin Finck 
1301c2c66affSColin Finck         /* Fix it up */
1302c2c66affSColin Finck         if(pbmiScaled->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
1303c2c66affSColin Finck         {
1304c2c66affSColin Finck             BITMAPCOREHEADER* pbmch = (BITMAPCOREHEADER*)&pbmiScaled->bmiHeader;
1305c2c66affSColin Finck             pbmch->bcWidth = cxDesired;
1306c2c66affSColin Finck             pbmch->bcHeight = cyDesired;
1307c2c66affSColin Finck         }
1308c2c66affSColin Finck         else
1309c2c66affSColin Finck         {
1310c2c66affSColin Finck             pbmiScaled->bmiHeader.biWidth = cxDesired;
1311c2c66affSColin Finck             pbmiScaled->bmiHeader.biHeight = cyDesired;
1312c2c66affSColin Finck             /* No compression for DIB sections */
1313c2c66affSColin Finck             pbmiScaled->bmiHeader.biCompression = BI_RGB;
1314c2c66affSColin Finck         }
1315c2c66affSColin Finck     }
1316c2c66affSColin Finck 
1317c2c66affSColin Finck     /* Top-down image */
1318c2c66affSColin Finck     if(cyDesired < 0) cyDesired = -cyDesired;
1319c2c66affSColin Finck 
1320c2c66affSColin Finck     /* We need a device context */
1321c2c66affSColin Finck     hdcScreen = CreateDCW(DISPLAYW, NULL, NULL, NULL);
1322c2c66affSColin Finck     if(!hdcScreen)
1323c2c66affSColin Finck         goto end;
1324c2c66affSColin Finck     hdc = CreateCompatibleDC(hdcScreen);
1325c2c66affSColin Finck     if(!hdc)
1326c2c66affSColin Finck         goto end;
1327c2c66affSColin Finck 
1328c2c66affSColin Finck     /* Now create the bitmap */
1329c2c66affSColin Finck     if(fuLoad & LR_CREATEDIBSECTION)
1330c2c66affSColin Finck         hbmpRet = CreateDIBSection(hdc, pbmiScaled, DIB_RGB_COLORS, NULL, 0, 0);
1331c2c66affSColin Finck     else
1332c2c66affSColin Finck     {
1333c2c66affSColin Finck         if(is_dib_monochrome(pbmiCopy) || (fuLoad & LR_MONOCHROME))
1334c2c66affSColin Finck             hbmpRet = CreateBitmap(cxDesired, cyDesired, 1, 1, NULL);
1335c2c66affSColin Finck         else
1336c2c66affSColin Finck             hbmpRet = CreateCompatibleBitmap(hdcScreen, cxDesired, cyDesired);
1337c2c66affSColin Finck     }
1338c2c66affSColin Finck 
1339c2c66affSColin Finck     if(!hbmpRet)
1340c2c66affSColin Finck         goto end;
1341c2c66affSColin Finck 
1342c2c66affSColin Finck     hbmpOld = SelectObject(hdc, hbmpRet);
1343c2c66affSColin Finck     if(!hbmpOld)
1344c2c66affSColin Finck         goto end;
1345c2c66affSColin Finck     if(!StretchDIBits(hdc, 0, 0, cxDesired, cyDesired,
1346c2c66affSColin Finck                            0, 0, width, height,
1347c2c66affSColin Finck                            pvBits, pbmiCopy, DIB_RGB_COLORS, SRCCOPY))
1348c2c66affSColin Finck     {
1349c2c66affSColin Finck         ERR("StretchDIBits failed!.\n");
1350c2c66affSColin Finck         SelectObject(hdc, hbmpOld);
1351c2c66affSColin Finck         DeleteObject(hbmpRet);
1352c2c66affSColin Finck         hbmpRet = NULL;
1353c2c66affSColin Finck         goto end;
1354c2c66affSColin Finck     }
1355c2c66affSColin Finck 
1356c2c66affSColin Finck     SelectObject(hdc, hbmpOld);
1357c2c66affSColin Finck 
1358c2c66affSColin Finck end:
1359c2c66affSColin Finck     if(hdcScreen)
1360c2c66affSColin Finck         DeleteDC(hdcScreen);
1361c2c66affSColin Finck     if(hdc)
1362c2c66affSColin Finck         DeleteDC(hdc);
1363c2c66affSColin Finck     if(pbmiScaled)
1364c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, pbmiScaled);
1365c2c66affSColin Finck     if(pbmiCopy)
1366c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, pbmiCopy);
1367c2c66affSColin Finck     if (pvMapping)
1368c2c66affSColin Finck         UnmapViewOfFile( pvMapping );
1369c2c66affSColin Finck     if(hgRsrc)
1370c2c66affSColin Finck         FreeResource(hgRsrc);
1371c2c66affSColin Finck 
1372c2c66affSColin Finck     return hbmpRet;
1373c2c66affSColin Finck }
1374c2c66affSColin Finck 
1375c2c66affSColin Finck 
1376c2c66affSColin Finck static
1377c2c66affSColin Finck HANDLE
CURSORICON_LoadFromFileW(_In_ LPCWSTR lpszName,_In_ int cxDesired,_In_ int cyDesired,_In_ UINT fuLoad,_In_ BOOL bIcon)1378c2c66affSColin Finck CURSORICON_LoadFromFileW(
1379c2c66affSColin Finck   _In_      LPCWSTR lpszName,
1380c2c66affSColin Finck   _In_      int cxDesired,
1381c2c66affSColin Finck   _In_      int cyDesired,
1382c2c66affSColin Finck   _In_      UINT fuLoad,
1383c2c66affSColin Finck   _In_      BOOL bIcon
1384c2c66affSColin Finck )
1385c2c66affSColin Finck {
1386c2c66affSColin Finck     const CURSORICONFILEDIRENTRY *entry;
1387c2c66affSColin Finck     const CURSORICONFILEDIR *dir;
1388c2c66affSColin Finck     DWORD filesize = 0;
1389c2c66affSColin Finck     LPBYTE bits;
1390c2c66affSColin Finck     HANDLE hCurIcon = NULL;
1391c2c66affSColin Finck     CURSORDATA cursorData;
1392c2c66affSColin Finck 
1393c2c66affSColin Finck     TRACE("loading %s\n", debugstr_w( lpszName ));
1394c2c66affSColin Finck 
1395c2c66affSColin Finck     bits = map_fileW( lpszName, &filesize );
1396c2c66affSColin Finck     if (!bits)
1397c2c66affSColin Finck         return NULL;
1398c2c66affSColin Finck 
1399c2c66affSColin Finck     /* Check for .ani. */
1400c2c66affSColin Finck     if (memcmp( bits, "RIFF", 4 ) == 0)
1401c2c66affSColin Finck     {
1402c2c66affSColin Finck         UNIMPLEMENTED;
1403c2c66affSColin Finck         goto end;
1404c2c66affSColin Finck     }
1405c2c66affSColin Finck 
1406c2c66affSColin Finck     dir = (CURSORICONFILEDIR*) bits;
1407c2c66affSColin Finck     entry = get_best_icon_file_entry(dir, filesize, cxDesired, cyDesired, bIcon, fuLoad);
1408c2c66affSColin Finck     if(!entry)
1409c2c66affSColin Finck         goto end;
1410c2c66affSColin Finck 
1411c2c66affSColin Finck     /* Fix dimensions */
1412c2c66affSColin Finck     if(!cxDesired) cxDesired = entry->bWidth;
1413c2c66affSColin Finck     if(!cyDesired) cyDesired = entry->bHeight;
1414c2c66affSColin Finck     /* A bit of preparation */
1415c2c66affSColin Finck     ZeroMemory(&cursorData, sizeof(cursorData));
1416c2c66affSColin Finck     if(!bIcon)
1417c2c66affSColin Finck     {
1418c2c66affSColin Finck         cursorData.xHotspot = entry->xHotspot;
1419c2c66affSColin Finck         cursorData.yHotspot = entry->yHotspot;
1420c2c66affSColin Finck     }
1421c2c66affSColin Finck     cursorData.rt = (USHORT)((ULONG_PTR)(bIcon ? RT_ICON : RT_CURSOR));
1422c2c66affSColin Finck 
1423c2c66affSColin Finck     /* Do the dance */
1424c2c66affSColin Finck     if(!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO*)(&bits[entry->dwDIBOffset])))
1425afd39cbcSDoug Lyons         {
1426afd39cbcSDoug Lyons             ERR("Failing File is \n    '%S'.\n", lpszName);
1427c2c66affSColin Finck             goto end;
1428afd39cbcSDoug Lyons         }
1429c2c66affSColin Finck 
1430c2c66affSColin Finck     hCurIcon = NtUserxCreateEmptyCurObject(FALSE);
1431c2c66affSColin Finck     if(!hCurIcon)
1432c2c66affSColin Finck         goto end;
1433c2c66affSColin Finck 
1434c2c66affSColin Finck     /* Tell win32k */
1435c2c66affSColin Finck     if(!NtUserSetCursorIconData(hCurIcon, NULL, NULL, &cursorData))
1436c2c66affSColin Finck     {
1437c2c66affSColin Finck         NtUserDestroyCursor(hCurIcon, TRUE);
1438c2c66affSColin Finck         goto end_error;
1439c2c66affSColin Finck     }
1440c2c66affSColin Finck 
1441c2c66affSColin Finck end:
1442c2c66affSColin Finck     UnmapViewOfFile(bits);
1443c2c66affSColin Finck     return hCurIcon;
1444c2c66affSColin Finck 
1445c2c66affSColin Finck     /* Clean up */
1446c2c66affSColin Finck end_error:
1447c2c66affSColin Finck     DeleteObject(cursorData.hbmMask);
1448c2c66affSColin Finck     if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor);
1449c2c66affSColin Finck     if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha);
1450c2c66affSColin Finck     UnmapViewOfFile(bits);
1451c2c66affSColin Finck 
1452c2c66affSColin Finck     return NULL;
1453c2c66affSColin Finck }
1454c2c66affSColin Finck 
1455c2c66affSColin Finck static
1456c2c66affSColin Finck HANDLE
CURSORICON_LoadImageW(_In_opt_ HINSTANCE hinst,_In_ LPCWSTR lpszName,_In_ int cxDesired,_In_ int cyDesired,_In_ UINT fuLoad,_In_ BOOL bIcon)1457c2c66affSColin Finck CURSORICON_LoadImageW(
1458c2c66affSColin Finck   _In_opt_  HINSTANCE hinst,
1459c2c66affSColin Finck   _In_      LPCWSTR lpszName,
1460c2c66affSColin Finck   _In_      int cxDesired,
1461c2c66affSColin Finck   _In_      int cyDesired,
1462c2c66affSColin Finck   _In_      UINT fuLoad,
1463c2c66affSColin Finck   _In_      BOOL bIcon
1464c2c66affSColin Finck )
1465c2c66affSColin Finck {
1466c2c66affSColin Finck     HRSRC hrsrc;
1467c2c66affSColin Finck     HANDLE handle, hCurIcon = NULL;
1468c2c66affSColin Finck     CURSORICONDIR* dir;
1469c2c66affSColin Finck     WORD wResId;
1470c2c66affSColin Finck     LPBYTE bits;
1471c2c66affSColin Finck     CURSORDATA cursorData;
1472c2c66affSColin Finck     BOOL bStatus;
1473c2c66affSColin Finck     UNICODE_STRING ustrRsrc;
1474c2c66affSColin Finck     UNICODE_STRING ustrModule = {0, 0, NULL};
1475c2c66affSColin Finck 
1476c2c66affSColin Finck     /* Fix width/height */
1477c2c66affSColin Finck     if(fuLoad & LR_DEFAULTSIZE)
1478c2c66affSColin Finck     {
1479c2c66affSColin Finck         if(!cxDesired) cxDesired = GetSystemMetrics(bIcon ? SM_CXICON : SM_CXCURSOR);
1480c2c66affSColin Finck         if(!cyDesired) cyDesired = GetSystemMetrics(bIcon ? SM_CYICON : SM_CYCURSOR);
1481c2c66affSColin Finck     }
1482c2c66affSColin Finck 
1483c2c66affSColin Finck     if(fuLoad & LR_LOADFROMFILE)
1484c2c66affSColin Finck     {
1485c2c66affSColin Finck         return CURSORICON_LoadFromFileW(lpszName, cxDesired, cyDesired, fuLoad, bIcon);
1486c2c66affSColin Finck     }
1487c2c66affSColin Finck 
1488c2c66affSColin Finck     /* Check if caller wants OEM icons */
1489c2c66affSColin Finck     if(!hinst)
1490c2c66affSColin Finck         hinst = User32Instance;
1491c2c66affSColin Finck 
1492c2c66affSColin Finck     if(lpszName)
1493c2c66affSColin Finck     {
1494c2c66affSColin Finck         /* Prepare the resource name string */
1495c2c66affSColin Finck         if(IS_INTRESOURCE(lpszName))
1496c2c66affSColin Finck         {
1497c2c66affSColin Finck             ustrRsrc.Buffer = (LPWSTR)lpszName;
1498c2c66affSColin Finck             ustrRsrc.Length = 0;
1499c2c66affSColin Finck             ustrRsrc.MaximumLength = 0;
1500c2c66affSColin Finck         }
1501c2c66affSColin Finck         else
1502c2c66affSColin Finck             RtlInitUnicodeString(&ustrRsrc, lpszName);
1503c2c66affSColin Finck     }
1504c2c66affSColin Finck 
150582c07abfSWhindmar Saksit     if(LDR_IS_RESOURCE(hinst))
150682c07abfSWhindmar Saksit     {
150782c07abfSWhindmar Saksit         /* We don't have a real module for GetModuleFileName, construct a fake name instead.
150882c07abfSWhindmar Saksit          * GetIconInfoEx reveals the name used by Windows. */
150982c07abfSWhindmar Saksit         LPCWSTR fakeNameFmt = sizeof(void*) > 4 ? L"\x01%016IX" : L"\x01%08IX";
151082c07abfSWhindmar Saksit         ustrModule.MaximumLength = 18 * sizeof(WCHAR);
151182c07abfSWhindmar Saksit         ustrModule.Buffer = HeapAlloc(GetProcessHeap(), 0, ustrModule.MaximumLength);
151282c07abfSWhindmar Saksit         if (!ustrModule.Buffer)
151382c07abfSWhindmar Saksit         {
151482c07abfSWhindmar Saksit             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
151582c07abfSWhindmar Saksit             return NULL;
151682c07abfSWhindmar Saksit         }
151782c07abfSWhindmar Saksit         ustrModule.Length = wsprintfW(ustrModule.Buffer, fakeNameFmt, hinst) * sizeof(WCHAR);
151882c07abfSWhindmar Saksit     }
151982c07abfSWhindmar Saksit     else if(hinst)
1520c2c66affSColin Finck     {
1521c2c66affSColin Finck         DWORD size = MAX_PATH;
1522c2c66affSColin Finck         /* Get the module name string */
1523c2c66affSColin Finck         while (TRUE)
1524c2c66affSColin Finck         {
1525c2c66affSColin Finck             DWORD ret;
1526c2c66affSColin Finck             ustrModule.Buffer = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR));
1527c2c66affSColin Finck             if (!ustrModule.Buffer)
1528c2c66affSColin Finck             {
1529c2c66affSColin Finck                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1530c2c66affSColin Finck                 return NULL;
1531c2c66affSColin Finck             }
1532c2c66affSColin Finck             ret = GetModuleFileNameW(hinst, ustrModule.Buffer, size);
1533c2c66affSColin Finck             if(ret == 0)
1534c2c66affSColin Finck             {
1535c2c66affSColin Finck                 HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
1536c2c66affSColin Finck                 return NULL;
1537c2c66affSColin Finck             }
1538c2c66affSColin Finck 
1539c2c66affSColin Finck             /* This API is completely broken... */
1540c2c66affSColin Finck             if (ret == size)
1541c2c66affSColin Finck             {
1542c2c66affSColin Finck                 HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
1543c2c66affSColin Finck                 size *= 2;
1544c2c66affSColin Finck                 continue;
1545c2c66affSColin Finck             }
1546c2c66affSColin Finck 
1547c2c66affSColin Finck             ustrModule.Buffer[ret] = UNICODE_NULL;
1548c2c66affSColin Finck             ustrModule.Length = ret * sizeof(WCHAR);
1549c2c66affSColin Finck             ustrModule.MaximumLength = size * sizeof(WCHAR);
1550c2c66affSColin Finck             break;
1551c2c66affSColin Finck         }
1552c2c66affSColin Finck     }
1553c2c66affSColin Finck 
1554c2c66affSColin Finck     if(fuLoad & LR_SHARED)
1555c2c66affSColin Finck     {
1556c2c66affSColin Finck         FINDEXISTINGCURICONPARAM param;
1557c2c66affSColin Finck 
1558c2c66affSColin Finck         TRACE("Checking for an LR_SHARED cursor/icon.\n");
1559c2c66affSColin Finck         /* Ask win32k */
1560c2c66affSColin Finck         param.bIcon = bIcon;
1561c2c66affSColin Finck         param.cx = cxDesired;
1562c2c66affSColin Finck         param.cy = cyDesired;
1563c2c66affSColin Finck         hCurIcon = NtUserFindExistingCursorIcon(&ustrModule, &ustrRsrc, &param);
1564c2c66affSColin Finck         if(hCurIcon)
1565c2c66affSColin Finck         {
1566c2c66affSColin Finck             /* Woohoo, got it! */
1567c2c66affSColin Finck             TRACE("MATCH! %p\n",hCurIcon);
1568c2c66affSColin Finck             HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
1569c2c66affSColin Finck             return hCurIcon;
1570c2c66affSColin Finck         }
1571c2c66affSColin Finck     }
1572c2c66affSColin Finck 
1573c2c66affSColin Finck     /* Find resource ID */
1574c2c66affSColin Finck     hrsrc = FindResourceW(
1575c2c66affSColin Finck         hinst,
1576c2c66affSColin Finck         lpszName,
1577c2c66affSColin Finck         bIcon ? RT_GROUP_ICON : RT_GROUP_CURSOR);
1578c2c66affSColin Finck 
1579c2c66affSColin Finck     /* We let FindResource, LoadResource, etc. call SetLastError */
1580c2c66affSColin Finck     if(!hrsrc)
1581c2c66affSColin Finck         goto done;
1582c2c66affSColin Finck 
1583c2c66affSColin Finck     handle = LoadResource(hinst, hrsrc);
1584c2c66affSColin Finck     if(!handle)
1585c2c66affSColin Finck         goto done;
1586c2c66affSColin Finck 
1587c2c66affSColin Finck     dir = LockResource(handle);
1588c2c66affSColin Finck     if(!dir)
1589c2c66affSColin Finck         goto done;
1590c2c66affSColin Finck 
1591c2c66affSColin Finck     wResId = LookupIconIdFromDirectoryEx((PBYTE)dir, bIcon, cxDesired, cyDesired, fuLoad);
1592c2c66affSColin Finck     FreeResource(handle);
1593c2c66affSColin Finck 
1594c2c66affSColin Finck     /* Get the relevant resource pointer */
1595c2c66affSColin Finck     hrsrc = FindResourceW(
1596c2c66affSColin Finck         hinst,
1597c2c66affSColin Finck         MAKEINTRESOURCEW(wResId),
1598c2c66affSColin Finck         bIcon ? RT_ICON : RT_CURSOR);
1599c2c66affSColin Finck     if(!hrsrc)
1600c2c66affSColin Finck         goto done;
1601c2c66affSColin Finck 
1602c2c66affSColin Finck     handle = LoadResource(hinst, hrsrc);
1603c2c66affSColin Finck     if(!handle)
1604c2c66affSColin Finck         goto done;
1605c2c66affSColin Finck 
1606c2c66affSColin Finck     bits = LockResource(handle);
1607c2c66affSColin Finck     if(!bits)
1608c2c66affSColin Finck     {
1609c2c66affSColin Finck         FreeResource(handle);
1610c2c66affSColin Finck         goto done;
1611c2c66affSColin Finck     }
1612c2c66affSColin Finck 
1613c2c66affSColin Finck     ZeroMemory(&cursorData, sizeof(cursorData));
1614c2c66affSColin Finck 
1615c2c66affSColin Finck     /* This is from resource */
1616c2c66affSColin Finck     cursorData.CURSORF_flags = CURSORF_FROMRESOURCE;
1617c2c66affSColin Finck 
1618c2c66affSColin Finck     if(dir->idType == 2)
1619c2c66affSColin Finck     {
1620c2c66affSColin Finck         /* idType == 2 for cursor resources */
1621c2c66affSColin Finck         SHORT* ptr = (SHORT*)bits;
1622c2c66affSColin Finck         cursorData.xHotspot = ptr[0];
1623c2c66affSColin Finck         cursorData.yHotspot = ptr[1];
1624c2c66affSColin Finck         bits += 2*sizeof(SHORT);
1625c2c66affSColin Finck     }
1626c2c66affSColin Finck     cursorData.cx = cxDesired;
1627c2c66affSColin Finck     cursorData.cy = cyDesired;
1628c2c66affSColin Finck     cursorData.rt = (USHORT)((ULONG_PTR)(bIcon ? RT_ICON : RT_CURSOR));
1629c2c66affSColin Finck 
1630c2c66affSColin Finck     /* Get the bitmaps */
1631c2c66affSColin Finck     bStatus = CURSORICON_GetCursorDataFromBMI(
1632c2c66affSColin Finck         &cursorData,
1633c2c66affSColin Finck         (BITMAPINFO*)bits);
1634c2c66affSColin Finck 
1635c2c66affSColin Finck     FreeResource( handle );
1636c2c66affSColin Finck 
1637c2c66affSColin Finck     if(!bStatus)
1638c2c66affSColin Finck         goto done;
1639c2c66affSColin Finck 
1640c2c66affSColin Finck     /* Create the handle */
1641c2c66affSColin Finck     hCurIcon = NtUserxCreateEmptyCurObject(FALSE);
1642c2c66affSColin Finck     if(!hCurIcon)
1643c2c66affSColin Finck     {
1644c2c66affSColin Finck         goto end_error;
1645c2c66affSColin Finck     }
1646c2c66affSColin Finck 
1647c2c66affSColin Finck     if(fuLoad & LR_SHARED)
1648c2c66affSColin Finck     {
1649c2c66affSColin Finck         cursorData.CURSORF_flags |= CURSORF_LRSHARED;
1650c2c66affSColin Finck     }
1651c2c66affSColin Finck 
1652c2c66affSColin Finck     /* Tell win32k */
1653c2c66affSColin Finck     bStatus = NtUserSetCursorIconData(hCurIcon, hinst ? &ustrModule : NULL, lpszName ? &ustrRsrc : NULL, &cursorData);
1654c2c66affSColin Finck 
1655c2c66affSColin Finck     if(!bStatus)
1656c2c66affSColin Finck     {
1657c2c66affSColin Finck         NtUserDestroyCursor(hCurIcon, TRUE);
1658c2c66affSColin Finck         goto end_error;
1659c2c66affSColin Finck     }
1660c2c66affSColin Finck 
1661c2c66affSColin Finck done:
1662c2c66affSColin Finck     if(ustrModule.Buffer)
1663c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
1664c2c66affSColin Finck     return hCurIcon;
1665c2c66affSColin Finck 
1666c2c66affSColin Finck end_error:
1667c2c66affSColin Finck     if(ustrModule.Buffer)
1668c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
1669c2c66affSColin Finck     DeleteObject(cursorData.hbmMask);
1670c2c66affSColin Finck     if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor);
1671c2c66affSColin Finck     if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha);
1672c2c66affSColin Finck 
1673c2c66affSColin Finck     return NULL;
1674c2c66affSColin Finck }
1675c2c66affSColin Finck 
1676c2c66affSColin Finck static
1677c2c66affSColin Finck HBITMAP
BITMAP_CopyImage(_In_ HBITMAP hnd,_In_ int desiredx,_In_ int desiredy,_In_ UINT flags)1678c2c66affSColin Finck BITMAP_CopyImage(
1679c2c66affSColin Finck   _In_  HBITMAP hnd,
1680c2c66affSColin Finck   _In_  int desiredx,
1681c2c66affSColin Finck   _In_  int desiredy,
1682c2c66affSColin Finck   _In_  UINT flags
1683c2c66affSColin Finck )
1684c2c66affSColin Finck {
1685c2c66affSColin Finck     HBITMAP res = NULL;
1686c2c66affSColin Finck     DIBSECTION ds;
1687c2c66affSColin Finck     int objSize;
1688c2c66affSColin Finck     BITMAPINFO * bi;
1689c2c66affSColin Finck 
1690c2c66affSColin Finck     objSize = GetObjectW( hnd, sizeof(ds), &ds );
1691c2c66affSColin Finck     if (!objSize) return 0;
1692c2c66affSColin Finck     if ((desiredx < 0) || (desiredy < 0)) return 0;
1693c2c66affSColin Finck 
1694c2c66affSColin Finck     if (flags & LR_COPYFROMRESOURCE)
1695c2c66affSColin Finck     {
1696c2c66affSColin Finck         FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
1697c2c66affSColin Finck     }
1698c2c66affSColin Finck 
1699c2c66affSColin Finck     if (flags & LR_COPYRETURNORG)
1700c2c66affSColin Finck     {
1701c2c66affSColin Finck         FIXME("The flag LR_COPYRETURNORG is not implemented for bitmaps\n");
1702c2c66affSColin Finck     }
1703c2c66affSColin Finck 
1704c2c66affSColin Finck     if (desiredx == 0) desiredx = ds.dsBm.bmWidth;
1705c2c66affSColin Finck     if (desiredy == 0) desiredy = ds.dsBm.bmHeight;
1706c2c66affSColin Finck 
1707c2c66affSColin Finck     /* Allocate memory for a BITMAPINFOHEADER structure and a
1708c2c66affSColin Finck        color table. The maximum number of colors in a color table
1709c2c66affSColin Finck        is 256 which corresponds to a bitmap with depth 8.
1710c2c66affSColin Finck        Bitmaps with higher depths don't have color tables. */
1711c2c66affSColin Finck     bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1712c2c66affSColin Finck     if (!bi) return 0;
1713c2c66affSColin Finck 
1714c2c66affSColin Finck     bi->bmiHeader.biSize        = sizeof(bi->bmiHeader);
1715c2c66affSColin Finck     bi->bmiHeader.biPlanes      = ds.dsBm.bmPlanes;
1716c2c66affSColin Finck     bi->bmiHeader.biBitCount    = ds.dsBm.bmBitsPixel;
1717c2c66affSColin Finck     bi->bmiHeader.biCompression = BI_RGB;
1718c2c66affSColin Finck 
1719c2c66affSColin Finck     if (flags & LR_CREATEDIBSECTION)
1720c2c66affSColin Finck     {
1721c2c66affSColin Finck         /* Create a DIB section. LR_MONOCHROME is ignored */
1722c2c66affSColin Finck         void * bits;
1723c2c66affSColin Finck         HDC dc = CreateCompatibleDC(NULL);
1724c2c66affSColin Finck 
1725c2c66affSColin Finck         if (objSize == sizeof(DIBSECTION))
1726c2c66affSColin Finck         {
1727c2c66affSColin Finck             /* The source bitmap is a DIB.
1728c2c66affSColin Finck                Get its attributes to create an exact copy */
1729c2c66affSColin Finck             memcpy(bi, &ds.dsBmih, sizeof(BITMAPINFOHEADER));
1730c2c66affSColin Finck         }
1731c2c66affSColin Finck 
1732c2c66affSColin Finck         bi->bmiHeader.biWidth  = desiredx;
1733c2c66affSColin Finck         bi->bmiHeader.biHeight = desiredy;
1734c2c66affSColin Finck 
1735c2c66affSColin Finck         /* Get the color table or the color masks */
1736c2c66affSColin Finck         GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
1737c2c66affSColin Finck 
1738c2c66affSColin Finck         res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
1739c2c66affSColin Finck         DeleteDC(dc);
1740c2c66affSColin Finck     }
1741c2c66affSColin Finck     else
1742c2c66affSColin Finck     {
1743c2c66affSColin Finck         /* Create a device-dependent bitmap */
1744c2c66affSColin Finck 
1745c2c66affSColin Finck         BOOL monochrome = (flags & LR_MONOCHROME);
1746c2c66affSColin Finck 
1747c2c66affSColin Finck         if (objSize == sizeof(DIBSECTION))
1748c2c66affSColin Finck         {
1749c2c66affSColin Finck             /* The source bitmap is a DIB section.
1750c2c66affSColin Finck                Get its attributes */
1751c2c66affSColin Finck             HDC dc = CreateCompatibleDC(NULL);
1752c2c66affSColin Finck             bi->bmiHeader.biWidth  = ds.dsBm.bmWidth;
1753c2c66affSColin Finck             bi->bmiHeader.biHeight = ds.dsBm.bmHeight;
1754c2c66affSColin Finck             GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
1755c2c66affSColin Finck             DeleteDC(dc);
1756c2c66affSColin Finck 
1757c2c66affSColin Finck             if (!monochrome && ds.dsBm.bmBitsPixel == 1)
1758c2c66affSColin Finck             {
1759c2c66affSColin Finck                 /* Look if the colors of the DIB are black and white */
1760c2c66affSColin Finck 
1761c2c66affSColin Finck                 monochrome =
1762c2c66affSColin Finck                       (bi->bmiColors[0].rgbRed == 0xff
1763c2c66affSColin Finck                     && bi->bmiColors[0].rgbGreen == 0xff
1764c2c66affSColin Finck                     && bi->bmiColors[0].rgbBlue == 0xff
1765c2c66affSColin Finck                     && bi->bmiColors[0].rgbReserved == 0
1766c2c66affSColin Finck                     && bi->bmiColors[1].rgbRed == 0
1767c2c66affSColin Finck                     && bi->bmiColors[1].rgbGreen == 0
1768c2c66affSColin Finck                     && bi->bmiColors[1].rgbBlue == 0
1769c2c66affSColin Finck                     && bi->bmiColors[1].rgbReserved == 0)
1770c2c66affSColin Finck                     ||
1771c2c66affSColin Finck                       (bi->bmiColors[0].rgbRed == 0
1772c2c66affSColin Finck                     && bi->bmiColors[0].rgbGreen == 0
1773c2c66affSColin Finck                     && bi->bmiColors[0].rgbBlue == 0
1774c2c66affSColin Finck                     && bi->bmiColors[0].rgbReserved == 0
1775c2c66affSColin Finck                     && bi->bmiColors[1].rgbRed == 0xff
1776c2c66affSColin Finck                     && bi->bmiColors[1].rgbGreen == 0xff
1777c2c66affSColin Finck                     && bi->bmiColors[1].rgbBlue == 0xff
1778c2c66affSColin Finck                     && bi->bmiColors[1].rgbReserved == 0);
1779c2c66affSColin Finck             }
1780c2c66affSColin Finck         }
1781c2c66affSColin Finck         else if (!monochrome)
1782c2c66affSColin Finck         {
1783c2c66affSColin Finck             monochrome = ds.dsBm.bmBitsPixel == 1;
1784c2c66affSColin Finck         }
1785c2c66affSColin Finck 
1786c2c66affSColin Finck         if (monochrome)
1787c2c66affSColin Finck         {
1788c2c66affSColin Finck             res = CreateBitmap(desiredx, desiredy, 1, 1, NULL);
1789c2c66affSColin Finck         }
1790c2c66affSColin Finck         else
1791c2c66affSColin Finck         {
1792c2c66affSColin Finck             HDC screenDC = GetDC(NULL);
1793c2c66affSColin Finck             res = CreateCompatibleBitmap(screenDC, desiredx, desiredy);
1794c2c66affSColin Finck             ReleaseDC(NULL, screenDC);
1795c2c66affSColin Finck         }
1796c2c66affSColin Finck     }
1797c2c66affSColin Finck 
1798c2c66affSColin Finck     if (res)
1799c2c66affSColin Finck     {
1800c2c66affSColin Finck         /* Only copy the bitmap if it's a DIB section or if it's
1801c2c66affSColin Finck            compatible to the screen */
1802c2c66affSColin Finck         BOOL copyContents;
1803c2c66affSColin Finck 
1804c2c66affSColin Finck         if (objSize == sizeof(DIBSECTION))
1805c2c66affSColin Finck         {
1806c2c66affSColin Finck             copyContents = TRUE;
1807c2c66affSColin Finck         }
1808c2c66affSColin Finck         else
1809c2c66affSColin Finck         {
1810c2c66affSColin Finck             HDC screenDC = GetDC(NULL);
1811c2c66affSColin Finck             int screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
1812c2c66affSColin Finck             ReleaseDC(NULL, screenDC);
1813c2c66affSColin Finck 
1814c2c66affSColin Finck             copyContents = (ds.dsBm.bmBitsPixel == 1 || ds.dsBm.bmBitsPixel == screen_depth);
1815c2c66affSColin Finck         }
1816c2c66affSColin Finck 
1817c2c66affSColin Finck         if (copyContents)
1818c2c66affSColin Finck         {
1819c2c66affSColin Finck             /* The source bitmap may already be selected in a device context,
1820c2c66affSColin Finck                use GetDIBits/StretchDIBits and not StretchBlt  */
1821c2c66affSColin Finck 
1822c2c66affSColin Finck             HDC dc;
1823c2c66affSColin Finck             void * bits;
1824c2c66affSColin Finck 
1825c2c66affSColin Finck             dc = CreateCompatibleDC(NULL);
1826c2c66affSColin Finck 
1827c2c66affSColin Finck             bi->bmiHeader.biWidth = ds.dsBm.bmWidth;
1828c2c66affSColin Finck             bi->bmiHeader.biHeight = ds.dsBm.bmHeight;
1829c2c66affSColin Finck             bi->bmiHeader.biSizeImage = 0;
1830c2c66affSColin Finck             bi->bmiHeader.biClrUsed = 0;
1831c2c66affSColin Finck             bi->bmiHeader.biClrImportant = 0;
1832c2c66affSColin Finck 
1833c2c66affSColin Finck             /* Fill in biSizeImage */
1834c2c66affSColin Finck             GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
1835c2c66affSColin Finck             bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bi->bmiHeader.biSizeImage);
1836c2c66affSColin Finck 
1837c2c66affSColin Finck             if (bits)
1838c2c66affSColin Finck             {
1839c2c66affSColin Finck                 HBITMAP oldBmp;
1840c2c66affSColin Finck 
1841c2c66affSColin Finck                 /* Get the image bits of the source bitmap */
1842c2c66affSColin Finck                 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS);
1843c2c66affSColin Finck 
1844c2c66affSColin Finck                 /* Copy it to the destination bitmap */
1845c2c66affSColin Finck                 oldBmp = SelectObject(dc, res);
1846c2c66affSColin Finck                 StretchDIBits(dc, 0, 0, desiredx, desiredy,
1847c2c66affSColin Finck                               0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight,
1848c2c66affSColin Finck                               bits, bi, DIB_RGB_COLORS, SRCCOPY);
1849c2c66affSColin Finck                 SelectObject(dc, oldBmp);
1850c2c66affSColin Finck 
1851c2c66affSColin Finck                 HeapFree(GetProcessHeap(), 0, bits);
1852c2c66affSColin Finck             }
1853c2c66affSColin Finck 
1854c2c66affSColin Finck             DeleteDC(dc);
1855c2c66affSColin Finck         }
1856c2c66affSColin Finck 
1857c2c66affSColin Finck         if (flags & LR_COPYDELETEORG)
1858c2c66affSColin Finck         {
1859c2c66affSColin Finck             DeleteObject(hnd);
1860c2c66affSColin Finck         }
1861c2c66affSColin Finck     }
1862c2c66affSColin Finck     HeapFree(GetProcessHeap(), 0, bi);
1863c2c66affSColin Finck     return res;
1864c2c66affSColin Finck }
1865c2c66affSColin Finck 
1866c2c66affSColin Finck static
1867c2c66affSColin Finck HICON
CURSORICON_CopyImage(_In_ HICON hicon,_In_ BOOL bIcon,_In_ int cxDesired,_In_ int cyDesired,_In_ UINT fuFlags)1868c2c66affSColin Finck CURSORICON_CopyImage(
1869c2c66affSColin Finck   _In_  HICON hicon,
1870c2c66affSColin Finck   _In_  BOOL  bIcon,
1871c2c66affSColin Finck   _In_  int cxDesired,
1872c2c66affSColin Finck   _In_  int cyDesired,
1873c2c66affSColin Finck   _In_  UINT fuFlags
1874c2c66affSColin Finck )
1875c2c66affSColin Finck {
1876c2c66affSColin Finck     HICON ret = NULL;
1877c2c66affSColin Finck     ICONINFO ii;
1878c2c66affSColin Finck     CURSORDATA CursorData;
1879c2c66affSColin Finck 
1880c2c66affSColin Finck     if (fuFlags & LR_COPYFROMRESOURCE)
1881c2c66affSColin Finck     {
1882c2c66affSColin Finck         /* Get the icon module/resource names */
1883c2c66affSColin Finck         UNICODE_STRING ustrModule;
1884c2c66affSColin Finck         UNICODE_STRING ustrRsrc;
1885c2c66affSColin Finck         HMODULE hModule;
1886c2c66affSColin Finck 
1887c2c66affSColin Finck         ustrModule.MaximumLength = 0;
1888c2c66affSColin Finck         ustrRsrc.MaximumLength = 0;
1889c2c66affSColin Finck 
1890c2c66affSColin Finck         /* Get the buffer size */
1891c2c66affSColin Finck         if (!NtUserGetIconInfo(hicon, NULL, &ustrModule, &ustrRsrc, NULL, FALSE))
1892c2c66affSColin Finck         {
1893c2c66affSColin Finck             return NULL;
1894c2c66affSColin Finck         }
1895c2c66affSColin Finck 
1896c2c66affSColin Finck         ustrModule.Buffer = HeapAlloc(GetProcessHeap(), 0, ustrModule.MaximumLength);
1897c2c66affSColin Finck         if (!ustrModule.Buffer)
1898c2c66affSColin Finck         {
1899c2c66affSColin Finck             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1900c2c66affSColin Finck             return NULL;
1901c2c66affSColin Finck         }
1902c2c66affSColin Finck 
1903c2c66affSColin Finck         if (ustrRsrc.MaximumLength)
1904c2c66affSColin Finck         {
1905c2c66affSColin Finck             ustrRsrc.Buffer = HeapAlloc(GetProcessHeap(), 0, ustrRsrc.MaximumLength);
1906c2c66affSColin Finck             if (!ustrRsrc.Buffer)
1907c2c66affSColin Finck             {
1908c2c66affSColin Finck                 HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
1909c2c66affSColin Finck                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1910c2c66affSColin Finck                 return NULL;
1911c2c66affSColin Finck             }
1912c2c66affSColin Finck         }
1913c2c66affSColin Finck 
1914c2c66affSColin Finck         if (!NtUserGetIconInfo(hicon, NULL, &ustrModule, &ustrRsrc, NULL, FALSE))
1915c2c66affSColin Finck         {
1916c2c66affSColin Finck             HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
1917c2c66affSColin Finck             if (!IS_INTRESOURCE(ustrRsrc.Buffer))
1918c2c66affSColin Finck                 HeapFree(GetProcessHeap(), 0, ustrRsrc.Buffer);
1919c2c66affSColin Finck             return NULL;
1920c2c66affSColin Finck         }
1921c2c66affSColin Finck 
1922c2c66affSColin Finck         /* NULL-terminate our strings */
1923c2c66affSColin Finck         ustrModule.Buffer[ustrModule.Length/sizeof(WCHAR)] = UNICODE_NULL;
1924c2c66affSColin Finck         if (!IS_INTRESOURCE(ustrRsrc.Buffer))
1925c2c66affSColin Finck             ustrRsrc.Buffer[ustrRsrc.Length/sizeof(WCHAR)] = UNICODE_NULL;
1926c2c66affSColin Finck 
1927c2c66affSColin Finck         TRACE("Got module %wZ, resource %p (%S).\n", &ustrModule,
1928c2c66affSColin Finck             ustrRsrc.Buffer, IS_INTRESOURCE(ustrRsrc.Buffer) ? L"" : ustrRsrc.Buffer);
1929c2c66affSColin Finck 
1930c2c66affSColin Finck         /* Get the module handle or load the module */
1931a0483167SSerge Gautherie         hModule = LoadLibraryExW(ustrModule.Buffer, NULL, /* NT6+: LOAD_LIBRARY_AS_IMAGE_RESOURCE | */ LOAD_LIBRARY_AS_DATAFILE);
1932c2c66affSColin Finck         if (!hModule)
1933c2c66affSColin Finck         {
1934c2c66affSColin Finck             DWORD err = GetLastError();
1935c2c66affSColin Finck             ERR("Unable to load/use module '%wZ' in process %lu, error %lu.\n", &ustrModule, GetCurrentProcessId(), err);
1936c2c66affSColin Finck             SetLastError(ERROR_INVALID_PARAMETER);
1937c2c66affSColin Finck             goto leave;
1938c2c66affSColin Finck         }
1939c2c66affSColin Finck 
1940c2c66affSColin Finck         /* Call the relevant function */
1941c2c66affSColin Finck         ret = CURSORICON_LoadImageW(
1942c2c66affSColin Finck             hModule,
1943c2c66affSColin Finck             ustrRsrc.Buffer,
1944c2c66affSColin Finck             cxDesired,
1945c2c66affSColin Finck             cyDesired,
1946c2c66affSColin Finck             fuFlags & (LR_DEFAULTSIZE | LR_SHARED),
1947c2c66affSColin Finck             bIcon);
1948c2c66affSColin Finck 
1949c2c66affSColin Finck         FreeLibrary(hModule);
1950c2c66affSColin Finck 
1951c2c66affSColin Finck         /* If we're here, that means that the passed icon is shared. Don't destroy it, even if LR_COPYDELETEORG is specified */
1952c2c66affSColin Finck     leave:
1953c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, ustrModule.Buffer);
1954c2c66affSColin Finck         if (!IS_INTRESOURCE(ustrRsrc.Buffer))
1955c2c66affSColin Finck             HeapFree(GetProcessHeap(), 0, ustrRsrc.Buffer);
1956c2c66affSColin Finck 
1957c2c66affSColin Finck         TRACE("Returning 0x%08x.\n", ret);
1958c2c66affSColin Finck 
1959c2c66affSColin Finck         return ret;
1960c2c66affSColin Finck     }
1961c2c66affSColin Finck 
1962c2c66affSColin Finck     /* This is a regular copy */
1963c2c66affSColin Finck     if (fuFlags & ~(LR_COPYDELETEORG | LR_SHARED))
1964c2c66affSColin Finck         FIXME("Unimplemented flags: 0x%08x\n", fuFlags);
1965c2c66affSColin Finck 
1966c2c66affSColin Finck     if (!GetIconInfo(hicon, &ii))
1967c2c66affSColin Finck     {
1968c2c66affSColin Finck         ERR("GetIconInfo failed.\n");
1969c2c66affSColin Finck         return NULL;
1970c2c66affSColin Finck     }
1971c2c66affSColin Finck 
1972c2c66affSColin Finck     /* This is CreateIconIndirect with the LR_SHARED coat added */
1973c2c66affSColin Finck     if  (!CURSORICON_GetCursorDataFromIconInfo(&CursorData, &ii))
1974c2c66affSColin Finck         goto Leave;
1975c2c66affSColin Finck 
1976c2c66affSColin Finck     if (fuFlags & LR_SHARED)
1977c2c66affSColin Finck         CursorData.CURSORF_flags |= CURSORF_LRSHARED;
1978c2c66affSColin Finck 
1979c2c66affSColin Finck     ret = NtUserxCreateEmptyCurObject(FALSE);
1980c2c66affSColin Finck     if (!ret)
1981c2c66affSColin Finck         goto Leave;
1982c2c66affSColin Finck 
1983c2c66affSColin Finck     if (!NtUserSetCursorIconData(ret, NULL, NULL, &CursorData))
1984c2c66affSColin Finck     {
1985c2c66affSColin Finck         NtUserDestroyCursor(ret, TRUE);
1986c2c66affSColin Finck         goto Leave;
1987c2c66affSColin Finck     }
1988c2c66affSColin Finck 
1989c2c66affSColin Finck Leave:
1990c2c66affSColin Finck     DeleteObject(ii.hbmMask);
1991c2c66affSColin Finck     if (ii.hbmColor) DeleteObject(ii.hbmColor);
1992c2c66affSColin Finck 
1993c2c66affSColin Finck     if (ret && (fuFlags & LR_COPYDELETEORG))
1994c2c66affSColin Finck         DestroyIcon(hicon);
1995c2c66affSColin Finck 
1996c2c66affSColin Finck     return ret;
1997c2c66affSColin Finck }
1998c2c66affSColin Finck 
1999c2c66affSColin Finck NTSTATUS WINAPI
User32CallCopyImageFromKernel(PVOID Arguments,ULONG ArgumentLength)2000c2c66affSColin Finck User32CallCopyImageFromKernel(PVOID Arguments, ULONG ArgumentLength)
2001c2c66affSColin Finck {
2002c2c66affSColin Finck   PCOPYIMAGE_CALLBACK_ARGUMENTS Common;
2003c2c66affSColin Finck   HANDLE Result;
2004c2c66affSColin Finck   Common = (PCOPYIMAGE_CALLBACK_ARGUMENTS) Arguments;
2005c2c66affSColin Finck 
2006c2c66affSColin Finck   Result = CopyImage(Common->hImage,
2007c2c66affSColin Finck                      Common->uType,
2008c2c66affSColin Finck                      Common->cxDesired,
2009c2c66affSColin Finck                      Common->cyDesired,
2010c2c66affSColin Finck                      Common->fuFlags);
2011c2c66affSColin Finck 
2012c2c66affSColin Finck   return ZwCallbackReturn(&Result, sizeof(HANDLE), STATUS_SUCCESS);
2013c2c66affSColin Finck }
2014c2c66affSColin Finck 
2015c2c66affSColin Finck 
2016c2c66affSColin Finck /************* PUBLIC FUNCTIONS *******************/
2017c2c66affSColin Finck 
2018efe42074SKatayama Hirofumi MZ #define COPYIMAGE_VALID_FLAGS ( \
2019efe42074SKatayama Hirofumi MZ     LR_SHARED | LR_COPYFROMRESOURCE | LR_CREATEDIBSECTION | LR_LOADMAP3DCOLORS | 0x800 | \
2020efe42074SKatayama Hirofumi MZ     LR_VGACOLOR | LR_LOADREALSIZE | LR_DEFAULTSIZE | LR_LOADTRANSPARENT | LR_LOADFROMFILE | \
2021efe42074SKatayama Hirofumi MZ     LR_COPYDELETEORG | LR_COPYRETURNORG | LR_COLOR | LR_MONOCHROME \
2022efe42074SKatayama Hirofumi MZ )
2023efe42074SKatayama Hirofumi MZ 
CopyImage(_In_ HANDLE hImage,_In_ UINT uType,_In_ int cxDesired,_In_ int cyDesired,_In_ UINT fuFlags)2024c2c66affSColin Finck HANDLE WINAPI CopyImage(
2025c2c66affSColin Finck   _In_  HANDLE hImage,
2026c2c66affSColin Finck   _In_  UINT uType,
2027c2c66affSColin Finck   _In_  int cxDesired,
2028c2c66affSColin Finck   _In_  int cyDesired,
2029c2c66affSColin Finck   _In_  UINT fuFlags
2030c2c66affSColin Finck )
2031c2c66affSColin Finck {
2032c2c66affSColin Finck     TRACE("hImage=%p, uType=%u, cxDesired=%d, cyDesired=%d, fuFlags=%x\n",
2033c2c66affSColin Finck         hImage, uType, cxDesired, cyDesired, fuFlags);
2034efe42074SKatayama Hirofumi MZ 
2035efe42074SKatayama Hirofumi MZ     if (fuFlags & ~COPYIMAGE_VALID_FLAGS)
2036efe42074SKatayama Hirofumi MZ     {
2037efe42074SKatayama Hirofumi MZ         SetLastError(ERROR_INVALID_PARAMETER);
2038efe42074SKatayama Hirofumi MZ         return NULL;
2039efe42074SKatayama Hirofumi MZ     }
2040efe42074SKatayama Hirofumi MZ 
2041c2c66affSColin Finck     switch(uType)
2042c2c66affSColin Finck     {
2043c2c66affSColin Finck         case IMAGE_BITMAP:
2044c2c66affSColin Finck             return BITMAP_CopyImage(hImage, cxDesired, cyDesired, fuFlags);
2045c2c66affSColin Finck         case IMAGE_CURSOR:
2046c2c66affSColin Finck         case IMAGE_ICON:
2047*d3ec7cddSJulen Urizar Compains         /* HACK: Copying bitmaps with LR_COPYFROMRESOURCE flag fails. CORE-17902.
2048*d3ec7cddSJulen Urizar Compains          * This is a way to return the original bit map if we need
2049*d3ec7cddSJulen Urizar Compains          * the icons to show up. We need a simpler test. */
2050*d3ec7cddSJulen Urizar Compains         {
2051*d3ec7cddSJulen Urizar Compains             HANDLE handle = CURSORICON_CopyImage(hImage, uType == IMAGE_ICON, cxDesired, cyDesired, fuFlags);
2052*d3ec7cddSJulen Urizar Compains             if (!handle && (fuFlags & (LR_COPYFROMRESOURCE|LR_COPYRETURNORG)))
2053*d3ec7cddSJulen Urizar Compains                 handle = CURSORICON_CopyImage(hImage, uType == IMAGE_ICON, cxDesired, cyDesired, (fuFlags & ~LR_COPYFROMRESOURCE));
2054*d3ec7cddSJulen Urizar Compains             return handle;
2055*d3ec7cddSJulen Urizar Compains         }
2056c2c66affSColin Finck         default:
2057c2c66affSColin Finck             SetLastError(ERROR_INVALID_PARAMETER);
2058c2c66affSColin Finck             break;
2059c2c66affSColin Finck     }
2060c2c66affSColin Finck     return NULL;
2061c2c66affSColin Finck }
2062c2c66affSColin Finck 
CopyIcon(_In_ HICON hIcon)2063c2c66affSColin Finck HICON WINAPI CopyIcon(
2064c2c66affSColin Finck   _In_  HICON hIcon
2065c2c66affSColin Finck )
2066c2c66affSColin Finck {
2067c2c66affSColin Finck     return CURSORICON_CopyImage(hIcon, FALSE, 0, 0, 0);
2068c2c66affSColin Finck }
2069c2c66affSColin Finck 
DrawIcon(_In_ HDC hDC,_In_ int X,_In_ int Y,_In_ HICON hIcon)2070c2c66affSColin Finck BOOL WINAPI DrawIcon(
2071c2c66affSColin Finck   _In_  HDC hDC,
2072c2c66affSColin Finck   _In_  int X,
2073c2c66affSColin Finck   _In_  int Y,
2074c2c66affSColin Finck   _In_  HICON hIcon
2075c2c66affSColin Finck )
2076c2c66affSColin Finck {
2077c2c66affSColin Finck     return DrawIconEx(hDC, X, Y, hIcon, 0, 0, 0, NULL, DI_NORMAL | DI_COMPAT | DI_DEFAULTSIZE);
2078c2c66affSColin Finck }
2079c2c66affSColin Finck 
DrawIconEx(_In_ HDC hdc,_In_ int xLeft,_In_ int yTop,_In_ HICON hIcon,_In_ int cxWidth,_In_ int cyWidth,_In_ UINT istepIfAniCur,_In_opt_ HBRUSH hbrFlickerFreeDraw,_In_ UINT diFlags)2080c2c66affSColin Finck BOOL WINAPI DrawIconEx(
2081c2c66affSColin Finck   _In_      HDC hdc,
2082c2c66affSColin Finck   _In_      int xLeft,
2083c2c66affSColin Finck   _In_      int yTop,
2084c2c66affSColin Finck   _In_      HICON hIcon,
2085c2c66affSColin Finck   _In_      int cxWidth,
2086c2c66affSColin Finck   _In_      int cyWidth,
2087c2c66affSColin Finck   _In_      UINT istepIfAniCur,
2088c2c66affSColin Finck   _In_opt_  HBRUSH hbrFlickerFreeDraw,
2089c2c66affSColin Finck   _In_      UINT diFlags
2090c2c66affSColin Finck )
2091c2c66affSColin Finck {
2092c2c66affSColin Finck     return NtUserDrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth,
2093c2c66affSColin Finck                             istepIfAniCur, hbrFlickerFreeDraw, diFlags,
2094c2c66affSColin Finck                             0, 0);
2095c2c66affSColin Finck }
2096c2c66affSColin Finck 
GetIconInfo(_In_ HICON hIcon,_Out_ PICONINFO piconinfo)2097c2c66affSColin Finck BOOL WINAPI GetIconInfo(
2098c2c66affSColin Finck   _In_   HICON hIcon,
2099c2c66affSColin Finck   _Out_  PICONINFO piconinfo
2100c2c66affSColin Finck )
2101c2c66affSColin Finck {
2102c2c66affSColin Finck     return NtUserGetIconInfo(hIcon, piconinfo, NULL, NULL, NULL, FALSE);
2103c2c66affSColin Finck }
2104c2c66affSColin Finck 
DestroyIcon(_In_ HICON hIcon)2105c2c66affSColin Finck BOOL WINAPI DestroyIcon(
2106c2c66affSColin Finck   _In_  HICON hIcon
2107c2c66affSColin Finck )
2108c2c66affSColin Finck {
2109c2c66affSColin Finck     return NtUserDestroyCursor(hIcon, FALSE);
2110c2c66affSColin Finck }
2111c2c66affSColin Finck 
LoadIconA(_In_opt_ HINSTANCE hInstance,_In_ LPCSTR lpIconName)2112c2c66affSColin Finck HICON WINAPI LoadIconA(
2113c2c66affSColin Finck   _In_opt_  HINSTANCE hInstance,
2114c2c66affSColin Finck   _In_      LPCSTR lpIconName
2115c2c66affSColin Finck )
2116c2c66affSColin Finck {
2117c2c66affSColin Finck     TRACE("%p, %s\n", hInstance, debugstr_a(lpIconName));
2118c2c66affSColin Finck 
2119c2c66affSColin Finck     return LoadImageA(hInstance,
2120c2c66affSColin Finck         lpIconName,
2121c2c66affSColin Finck         IMAGE_ICON,
2122c2c66affSColin Finck         0,
2123c2c66affSColin Finck         0,
2124c2c66affSColin Finck         LR_SHARED | LR_DEFAULTSIZE );
2125c2c66affSColin Finck }
2126c2c66affSColin Finck 
LoadIconW(_In_opt_ HINSTANCE hInstance,_In_ LPCWSTR lpIconName)2127c2c66affSColin Finck HICON WINAPI LoadIconW(
2128c2c66affSColin Finck   _In_opt_  HINSTANCE hInstance,
2129c2c66affSColin Finck   _In_      LPCWSTR lpIconName
2130c2c66affSColin Finck )
2131c2c66affSColin Finck {
2132c2c66affSColin Finck     TRACE("%p, %s\n", hInstance, debugstr_w(lpIconName));
2133c2c66affSColin Finck 
2134c2c66affSColin Finck     return LoadImageW(hInstance,
2135c2c66affSColin Finck         lpIconName,
2136c2c66affSColin Finck         IMAGE_ICON,
2137c2c66affSColin Finck         0,
2138c2c66affSColin Finck         0,
2139c2c66affSColin Finck         LR_SHARED | LR_DEFAULTSIZE );
2140c2c66affSColin Finck }
2141c2c66affSColin Finck 
LoadCursorA(_In_opt_ HINSTANCE hInstance,_In_ LPCSTR lpCursorName)2142c2c66affSColin Finck HCURSOR WINAPI LoadCursorA(
2143c2c66affSColin Finck   _In_opt_  HINSTANCE hInstance,
2144c2c66affSColin Finck   _In_      LPCSTR    lpCursorName
2145c2c66affSColin Finck )
2146c2c66affSColin Finck {
2147c2c66affSColin Finck     TRACE("%p, %s\n", hInstance, debugstr_a(lpCursorName));
2148c2c66affSColin Finck 
2149c2c66affSColin Finck     return LoadImageA(hInstance,
2150c2c66affSColin Finck         lpCursorName,
2151c2c66affSColin Finck         IMAGE_CURSOR,
2152c2c66affSColin Finck         0,
2153c2c66affSColin Finck         0,
2154c2c66affSColin Finck         LR_SHARED | LR_DEFAULTSIZE );
2155c2c66affSColin Finck }
2156c2c66affSColin Finck 
LoadCursorW(_In_opt_ HINSTANCE hInstance,_In_ LPCWSTR lpCursorName)2157c2c66affSColin Finck HCURSOR WINAPI LoadCursorW(
2158c2c66affSColin Finck   _In_opt_  HINSTANCE hInstance,
2159c2c66affSColin Finck   _In_      LPCWSTR   lpCursorName
2160c2c66affSColin Finck )
2161c2c66affSColin Finck {
2162c2c66affSColin Finck     TRACE("%p, %s\n", hInstance, debugstr_w(lpCursorName));
2163c2c66affSColin Finck 
2164c2c66affSColin Finck     return LoadImageW(hInstance,
2165c2c66affSColin Finck         lpCursorName,
2166c2c66affSColin Finck         IMAGE_CURSOR,
2167c2c66affSColin Finck         0,
2168c2c66affSColin Finck         0,
2169c2c66affSColin Finck         LR_SHARED | LR_DEFAULTSIZE );
2170c2c66affSColin Finck }
2171c2c66affSColin Finck 
LoadCursorFromFileA(_In_ LPCSTR lpFileName)2172c2c66affSColin Finck HCURSOR WINAPI LoadCursorFromFileA(
2173c2c66affSColin Finck   _In_  LPCSTR lpFileName
2174c2c66affSColin Finck )
2175c2c66affSColin Finck {
2176c2c66affSColin Finck     TRACE("%s\n", debugstr_a(lpFileName));
2177c2c66affSColin Finck 
2178c2c66affSColin Finck     return LoadImageA(NULL,
2179c2c66affSColin Finck         lpFileName,
2180c2c66affSColin Finck         IMAGE_CURSOR,
2181c2c66affSColin Finck         0,
2182c2c66affSColin Finck         0,
2183c2c66affSColin Finck         LR_LOADFROMFILE | LR_DEFAULTSIZE );
2184c2c66affSColin Finck }
2185c2c66affSColin Finck 
LoadCursorFromFileW(_In_ LPCWSTR lpFileName)2186c2c66affSColin Finck HCURSOR WINAPI LoadCursorFromFileW(
2187c2c66affSColin Finck   _In_  LPCWSTR lpFileName
2188c2c66affSColin Finck )
2189c2c66affSColin Finck {
2190c2c66affSColin Finck     TRACE("%s\n", debugstr_w(lpFileName));
2191c2c66affSColin Finck 
2192c2c66affSColin Finck     return LoadImageW(NULL,
2193c2c66affSColin Finck         lpFileName,
2194c2c66affSColin Finck         IMAGE_CURSOR,
2195c2c66affSColin Finck         0,
2196c2c66affSColin Finck         0,
2197c2c66affSColin Finck         LR_LOADFROMFILE | LR_DEFAULTSIZE );
2198c2c66affSColin Finck }
2199c2c66affSColin Finck 
LoadBitmapA(_In_opt_ HINSTANCE hInstance,_In_ LPCSTR lpBitmapName)2200c2c66affSColin Finck HBITMAP WINAPI LoadBitmapA(
2201c2c66affSColin Finck   _In_opt_  HINSTANCE hInstance,
2202c2c66affSColin Finck   _In_      LPCSTR lpBitmapName
2203c2c66affSColin Finck )
2204c2c66affSColin Finck {
2205c2c66affSColin Finck     TRACE("%p, %s\n", hInstance, debugstr_a(lpBitmapName));
2206c2c66affSColin Finck 
2207c2c66affSColin Finck     return LoadImageA(hInstance,
2208c2c66affSColin Finck         lpBitmapName,
2209c2c66affSColin Finck         IMAGE_BITMAP,
2210c2c66affSColin Finck         0,
2211c2c66affSColin Finck         0,
2212c2c66affSColin Finck         0);
2213c2c66affSColin Finck }
2214c2c66affSColin Finck 
LoadBitmapW(_In_opt_ HINSTANCE hInstance,_In_ LPCWSTR lpBitmapName)2215c2c66affSColin Finck HBITMAP WINAPI LoadBitmapW(
2216c2c66affSColin Finck   _In_opt_  HINSTANCE hInstance,
2217c2c66affSColin Finck   _In_      LPCWSTR lpBitmapName
2218c2c66affSColin Finck )
2219c2c66affSColin Finck {
2220c2c66affSColin Finck     TRACE("%p, %s\n", hInstance, debugstr_w(lpBitmapName));
2221c2c66affSColin Finck 
2222c2c66affSColin Finck     return LoadImageW(hInstance,
2223c2c66affSColin Finck         lpBitmapName,
2224c2c66affSColin Finck         IMAGE_BITMAP,
2225c2c66affSColin Finck         0,
2226c2c66affSColin Finck         0,
2227c2c66affSColin Finck         0);
2228c2c66affSColin Finck }
2229c2c66affSColin Finck 
LoadImageA(_In_opt_ HINSTANCE hinst,_In_ LPCSTR lpszName,_In_ UINT uType,_In_ int cxDesired,_In_ int cyDesired,_In_ UINT fuLoad)2230c2c66affSColin Finck HANDLE WINAPI LoadImageA(
2231c2c66affSColin Finck   _In_opt_  HINSTANCE hinst,
2232c2c66affSColin Finck   _In_      LPCSTR lpszName,
2233c2c66affSColin Finck   _In_      UINT uType,
2234c2c66affSColin Finck   _In_      int cxDesired,
2235c2c66affSColin Finck   _In_      int cyDesired,
2236c2c66affSColin Finck   _In_      UINT fuLoad
2237c2c66affSColin Finck )
2238c2c66affSColin Finck {
2239c2c66affSColin Finck     HANDLE res;
2240c2c66affSColin Finck     LPWSTR u_name;
2241c2c66affSColin Finck     DWORD len;
2242c2c66affSColin Finck 
2243c2c66affSColin Finck     if (IS_INTRESOURCE(lpszName))
2244c2c66affSColin Finck         return LoadImageW(hinst, (LPCWSTR)lpszName, uType, cxDesired, cyDesired, fuLoad);
2245c2c66affSColin Finck 
2246c2c66affSColin Finck     len = MultiByteToWideChar( CP_ACP, 0, lpszName, -1, NULL, 0 );
2247c2c66affSColin Finck     u_name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2248c2c66affSColin Finck     MultiByteToWideChar( CP_ACP, 0, lpszName, -1, u_name, len );
2249c2c66affSColin Finck 
2250c2c66affSColin Finck     res = LoadImageW(hinst, u_name, uType, cxDesired, cyDesired, fuLoad);
2251c2c66affSColin Finck     HeapFree(GetProcessHeap(), 0, u_name);
2252c2c66affSColin Finck     return res;
2253c2c66affSColin Finck }
2254c2c66affSColin Finck 
LoadImageW(_In_opt_ HINSTANCE hinst,_In_ LPCWSTR lpszName,_In_ UINT uType,_In_ int cxDesired,_In_ int cyDesired,_In_ UINT fuLoad)2255c2c66affSColin Finck HANDLE WINAPI LoadImageW(
2256c2c66affSColin Finck   _In_opt_  HINSTANCE hinst,
2257c2c66affSColin Finck   _In_      LPCWSTR lpszName,
2258c2c66affSColin Finck   _In_      UINT uType,
2259c2c66affSColin Finck   _In_      int cxDesired,
2260c2c66affSColin Finck   _In_      int cyDesired,
2261c2c66affSColin Finck   _In_      UINT fuLoad
2262c2c66affSColin Finck )
2263c2c66affSColin Finck {
2264c2c66affSColin Finck     TRACE("hinst 0x%p, name %s, uType 0x%08x, cxDesired %d, cyDesired %d, fuLoad 0x%08x.\n",
2265c2c66affSColin Finck         hinst, debugstr_w(lpszName), uType, cxDesired, cyDesired, fuLoad);
2266c2c66affSColin Finck     /* Redirect to each implementation */
2267c2c66affSColin Finck     switch(uType)
2268c2c66affSColin Finck     {
2269c2c66affSColin Finck         case IMAGE_BITMAP:
2270c2c66affSColin Finck             return BITMAP_LoadImageW(hinst, lpszName, cxDesired, cyDesired, fuLoad);
2271c2c66affSColin Finck         case IMAGE_CURSOR:
2272c2c66affSColin Finck         case IMAGE_ICON:
2273c2c66affSColin Finck             return CURSORICON_LoadImageW(hinst, lpszName, cxDesired, cyDesired, fuLoad, uType == IMAGE_ICON);
2274c2c66affSColin Finck         default:
2275c2c66affSColin Finck             SetLastError(ERROR_INVALID_PARAMETER);
2276c2c66affSColin Finck             break;
2277c2c66affSColin Finck     }
2278c2c66affSColin Finck     return NULL;
2279c2c66affSColin Finck }
2280c2c66affSColin Finck 
LookupIconIdFromDirectory(_In_ PBYTE presbits,_In_ BOOL fIcon)2281c2c66affSColin Finck int WINAPI LookupIconIdFromDirectory(
2282c2c66affSColin Finck   _In_  PBYTE presbits,
2283c2c66affSColin Finck   _In_  BOOL fIcon
2284c2c66affSColin Finck )
2285c2c66affSColin Finck {
2286c2c66affSColin Finck     return LookupIconIdFromDirectoryEx( presbits, fIcon,
2287c2c66affSColin Finck            fIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
2288c2c66affSColin Finck            fIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), fIcon ? 0 : LR_MONOCHROME );
2289c2c66affSColin Finck }
2290c2c66affSColin Finck 
LookupIconIdFromDirectoryEx(_In_ PBYTE presbits,_In_ BOOL fIcon,_In_ int cxDesired,_In_ int cyDesired,_In_ UINT Flags)2291c2c66affSColin Finck int WINAPI LookupIconIdFromDirectoryEx(
2292c2c66affSColin Finck   _In_  PBYTE presbits,
2293c2c66affSColin Finck   _In_  BOOL fIcon,
2294c2c66affSColin Finck   _In_  int cxDesired,
2295c2c66affSColin Finck   _In_  int cyDesired,
2296c2c66affSColin Finck   _In_  UINT Flags
2297c2c66affSColin Finck )
2298c2c66affSColin Finck {
2299c2c66affSColin Finck     WORD bppDesired;
2300c2c66affSColin Finck     CURSORICONDIR* dir = (CURSORICONDIR*)presbits;
2301c2c66affSColin Finck     CURSORICONDIRENTRY* entry;
2302c2c66affSColin Finck     int i, numMatch = 0, iIndex = -1;
2303c2c66affSColin Finck     WORD width, height, BitCount = 0;
2304c2c66affSColin Finck     BOOL notPaletted = FALSE;
2305c2c66affSColin Finck     ULONG bestScore = 0xFFFFFFFF, score;
2306c2c66affSColin Finck 
2307c2c66affSColin Finck     TRACE("%p, %x, %i, %i, %x.\n", presbits, fIcon, cxDesired, cyDesired, Flags);
2308c2c66affSColin Finck 
2309c2c66affSColin Finck     if(!(dir && !dir->idReserved && (dir->idType & 3)))
2310c2c66affSColin Finck     {
2311c2c66affSColin Finck         WARN("Invalid resource.\n");
2312c2c66affSColin Finck         return 0;
2313c2c66affSColin Finck     }
2314c2c66affSColin Finck 
2315c2c66affSColin Finck     if(Flags & LR_MONOCHROME)
2316c2c66affSColin Finck         bppDesired = 1;
2317c2c66affSColin Finck     else
2318c2c66affSColin Finck     {
2319c2c66affSColin Finck         HDC icScreen;
2320c2c66affSColin Finck         icScreen = CreateICW(DISPLAYW, NULL, NULL, NULL);
2321c2c66affSColin Finck         if(!icScreen)
2322c2c66affSColin Finck             return FALSE;
2323c2c66affSColin Finck 
2324c2c66affSColin Finck         bppDesired = GetDeviceCaps(icScreen, BITSPIXEL);
2325c2c66affSColin Finck         DeleteDC(icScreen);
2326c2c66affSColin Finck     }
2327c2c66affSColin Finck 
2328c2c66affSColin Finck     if(!cxDesired)
2329c2c66affSColin Finck         cxDesired = Flags & LR_DEFAULTSIZE ? GetSystemMetrics(fIcon ? SM_CXICON : SM_CXCURSOR) : 256;
2330c2c66affSColin Finck     if(!cyDesired)
2331c2c66affSColin Finck         cyDesired = Flags & LR_DEFAULTSIZE ? GetSystemMetrics(fIcon ? SM_CYICON : SM_CYCURSOR) : 256;
2332c2c66affSColin Finck 
2333c2c66affSColin Finck     /* Find the best match for the desired size */
2334c2c66affSColin Finck     for(i = 0; i < dir->idCount; i++)
2335c2c66affSColin Finck     {
2336c2c66affSColin Finck         entry = &dir->idEntries[i];
2337c2c66affSColin Finck         width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth;
2338c2c66affSColin Finck         /* Height is twice as big in cursor resources */
2339c2c66affSColin Finck         height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2;
2340c2c66affSColin Finck         /* 0 represents 256 */
2341c2c66affSColin Finck         if(!width) width = 256;
2342c2c66affSColin Finck         if(!height) height = 256;
2343c2c66affSColin Finck         /* Calculate the "score" (lower is better) */
2344c2c66affSColin Finck         score = 2*(abs(width - cxDesired) + abs(height - cyDesired));
2345c2c66affSColin Finck         if( score > bestScore)
2346c2c66affSColin Finck             continue;
2347c2c66affSColin Finck         /* Bigger than requested lowers the score */
2348c2c66affSColin Finck         if(width > cxDesired)
2349c2c66affSColin Finck             score -= width - cxDesired;
2350c2c66affSColin Finck         if(height > cyDesired)
2351c2c66affSColin Finck             score -= height - cyDesired;
2352c2c66affSColin Finck         if(score > bestScore)
2353c2c66affSColin Finck             continue;
2354c2c66affSColin Finck         if(score == bestScore)
2355c2c66affSColin Finck         {
2356c2c66affSColin Finck             if(entry->wBitCount > BitCount)
2357c2c66affSColin Finck                 BitCount = entry->wBitCount;
2358c2c66affSColin Finck             numMatch++;
2359c2c66affSColin Finck             continue;
2360c2c66affSColin Finck         }
2361c2c66affSColin Finck         iIndex = i;
2362c2c66affSColin Finck         numMatch = 1;
2363c2c66affSColin Finck         bestScore = score;
2364c2c66affSColin Finck         BitCount = entry->wBitCount;
2365c2c66affSColin Finck     }
2366c2c66affSColin Finck 
2367c2c66affSColin Finck     if(numMatch == 1)
2368c2c66affSColin Finck     {
2369c2c66affSColin Finck         /* Only one entry fits the asked dimensions */
2370c2c66affSColin Finck         return dir->idEntries[iIndex].wResId;
2371c2c66affSColin Finck     }
2372c2c66affSColin Finck 
2373c2c66affSColin Finck     /* Avoid paletted icons on non-paletted device */
2374c2c66affSColin Finck     if (bppDesired > 8 && BitCount > 8)
2375c2c66affSColin Finck         notPaletted = TRUE;
2376c2c66affSColin Finck 
2377c2c66affSColin Finck     BitCount = 0;
2378c2c66affSColin Finck     iIndex = -1;
2379c2c66affSColin Finck     /* Now find the entry with the best depth */
2380c2c66affSColin Finck     for(i = 0; i < dir->idCount; i++)
2381c2c66affSColin Finck     {
2382c2c66affSColin Finck         entry = &dir->idEntries[i];
2383c2c66affSColin Finck         width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth;
2384c2c66affSColin Finck         height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2;
2385c2c66affSColin Finck         /* 0 represents 256 */
2386c2c66affSColin Finck         if(!width) width = 256;
2387c2c66affSColin Finck         if(!height) height = 256;
2388c2c66affSColin Finck         /* Check if this is the best match we had */
2389c2c66affSColin Finck         score = 2*(abs(width - cxDesired) + abs(height - cyDesired));
2390c2c66affSColin Finck         if(width > cxDesired)
2391c2c66affSColin Finck             score -= width - cxDesired;
2392c2c66affSColin Finck         if(height > cyDesired)
2393c2c66affSColin Finck             score -= height - cyDesired;
2394c2c66affSColin Finck         if(score != bestScore)
2395c2c66affSColin Finck             continue;
2396c2c66affSColin Finck         /* Exact match? */
2397c2c66affSColin Finck         if(entry->wBitCount == bppDesired)
2398c2c66affSColin Finck             return entry->wResId;
2399c2c66affSColin Finck         /* We take the highest possible but smaller  than the display depth */
2400c2c66affSColin Finck         if((entry->wBitCount > BitCount) && (entry->wBitCount < bppDesired))
2401c2c66affSColin Finck         {
2402c2c66affSColin Finck             /* Avoid paletted icons on non paletted devices */
2403c2c66affSColin Finck             if ((entry->wBitCount <= 8) && notPaletted)
2404c2c66affSColin Finck                 continue;
2405c2c66affSColin Finck             iIndex = i;
2406c2c66affSColin Finck             BitCount = entry->wBitCount;
2407c2c66affSColin Finck         }
2408c2c66affSColin Finck     }
2409c2c66affSColin Finck 
2410c2c66affSColin Finck     if(iIndex >= 0)
2411c2c66affSColin Finck         return dir->idEntries[iIndex].wResId;
2412c2c66affSColin Finck 
2413c2c66affSColin Finck     /* No inferior or equal depth available. Get the smallest bigger one */
2414c2c66affSColin Finck     BitCount = 0xFFFF;
2415c2c66affSColin Finck     iIndex = -1;
2416c2c66affSColin Finck     for(i = 0; i < dir->idCount; i++)
2417c2c66affSColin Finck     {
2418c2c66affSColin Finck         entry = &dir->idEntries[i];
2419c2c66affSColin Finck         width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth;
2420c2c66affSColin Finck         height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2;
2421c2c66affSColin Finck         /* 0 represents 256 */
2422c2c66affSColin Finck         if(!width) width = 256;
2423c2c66affSColin Finck         if(!height) height = 256;
2424c2c66affSColin Finck         /* Check if this is the best match we had */
2425c2c66affSColin Finck         score = 2*(abs(width - cxDesired) + abs(height - cyDesired));
2426c2c66affSColin Finck         if(width > cxDesired)
2427c2c66affSColin Finck             score -= width - cxDesired;
2428c2c66affSColin Finck         if(height > cyDesired)
2429c2c66affSColin Finck             score -= height - cyDesired;
2430c2c66affSColin Finck         if(score != bestScore)
2431c2c66affSColin Finck             continue;
2432c2c66affSColin Finck         /* Check the bit depth */
2433c2c66affSColin Finck         if(entry->wBitCount < BitCount)
2434c2c66affSColin Finck         {
2435c2c66affSColin Finck             if((entry->wBitCount <= 8) && notPaletted)
2436c2c66affSColin Finck                 continue;
2437c2c66affSColin Finck             iIndex = i;
2438c2c66affSColin Finck             BitCount = entry->wBitCount;
2439c2c66affSColin Finck         }
2440c2c66affSColin Finck     }
2441c2c66affSColin Finck     if (iIndex >= 0)
2442c2c66affSColin Finck         return dir->idEntries[iIndex].wResId;
2443c2c66affSColin Finck 
2444c2c66affSColin Finck     return 0;
2445c2c66affSColin Finck }
2446c2c66affSColin Finck 
CreateIcon(_In_opt_ HINSTANCE hInstance,_In_ int nWidth,_In_ int nHeight,_In_ BYTE cPlanes,_In_ BYTE cBitsPixel,_In_ const BYTE * lpbANDbits,_In_ const BYTE * lpbXORbits)2447c2c66affSColin Finck HICON WINAPI CreateIcon(
2448c2c66affSColin Finck   _In_opt_  HINSTANCE hInstance,
2449c2c66affSColin Finck   _In_      int nWidth,
2450c2c66affSColin Finck   _In_      int nHeight,
2451c2c66affSColin Finck   _In_      BYTE cPlanes,
2452c2c66affSColin Finck   _In_      BYTE cBitsPixel,
2453c2c66affSColin Finck   _In_      const BYTE *lpbANDbits,
2454c2c66affSColin Finck   _In_      const BYTE *lpbXORbits
2455c2c66affSColin Finck )
2456c2c66affSColin Finck {
2457c2c66affSColin Finck     ICONINFO iinfo;
2458c2c66affSColin Finck     HICON hIcon;
2459c2c66affSColin Finck 
2460c2c66affSColin Finck     TRACE_(icon)("%dx%d, planes %d, bpp %d, xor %p, and %p\n",
2461c2c66affSColin Finck                  nWidth, nHeight, cPlanes, cBitsPixel, lpbXORbits, lpbANDbits);
2462c2c66affSColin Finck 
2463c2c66affSColin Finck     iinfo.fIcon = TRUE;
2464c2c66affSColin Finck     iinfo.xHotspot = nWidth / 2;
2465c2c66affSColin Finck     iinfo.yHotspot = nHeight / 2;
2466c2c66affSColin Finck     if (cPlanes * cBitsPixel > 1)
2467c2c66affSColin Finck     {
2468c2c66affSColin Finck         iinfo.hbmColor = CreateBitmap( nWidth, nHeight, cPlanes, cBitsPixel, lpbXORbits );
2469c2c66affSColin Finck         iinfo.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpbANDbits );
2470c2c66affSColin Finck     }
2471c2c66affSColin Finck     else
2472c2c66affSColin Finck     {
2473c2c66affSColin Finck         iinfo.hbmMask = CreateBitmap( nWidth, nHeight * 2, 1, 1, lpbANDbits );
2474c2c66affSColin Finck         iinfo.hbmColor = NULL;
2475c2c66affSColin Finck     }
2476c2c66affSColin Finck 
2477c2c66affSColin Finck     hIcon = CreateIconIndirect( &iinfo );
2478c2c66affSColin Finck 
2479c2c66affSColin Finck     DeleteObject( iinfo.hbmMask );
2480c2c66affSColin Finck     if (iinfo.hbmColor) DeleteObject( iinfo.hbmColor );
2481c2c66affSColin Finck 
2482c2c66affSColin Finck     return hIcon;
2483c2c66affSColin Finck }
2484c2c66affSColin Finck 
CreateIconFromResource(_In_ PBYTE presbits,_In_ DWORD dwResSize,_In_ BOOL fIcon,_In_ DWORD dwVer)2485c2c66affSColin Finck HICON WINAPI CreateIconFromResource(
2486c2c66affSColin Finck   _In_  PBYTE presbits,
2487c2c66affSColin Finck   _In_  DWORD dwResSize,
2488c2c66affSColin Finck   _In_  BOOL fIcon,
2489c2c66affSColin Finck   _In_  DWORD dwVer
2490c2c66affSColin Finck )
2491c2c66affSColin Finck {
2492c2c66affSColin Finck     return CreateIconFromResourceEx( presbits, dwResSize, fIcon, dwVer, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
2493c2c66affSColin Finck }
2494c2c66affSColin Finck 
CreateIconFromResourceEx(_In_ PBYTE pbIconBits,_In_ DWORD cbIconBits,_In_ BOOL fIcon,_In_ DWORD dwVersion,_In_ int cxDesired,_In_ int cyDesired,_In_ UINT uFlags)2495c2c66affSColin Finck HICON WINAPI CreateIconFromResourceEx(
2496c2c66affSColin Finck   _In_  PBYTE pbIconBits,
2497c2c66affSColin Finck   _In_  DWORD cbIconBits,
2498c2c66affSColin Finck   _In_  BOOL fIcon,
2499c2c66affSColin Finck   _In_  DWORD dwVersion,
2500c2c66affSColin Finck   _In_  int cxDesired,
2501c2c66affSColin Finck   _In_  int cyDesired,
2502c2c66affSColin Finck   _In_  UINT uFlags
2503c2c66affSColin Finck )
2504c2c66affSColin Finck {
2505c2c66affSColin Finck     CURSORDATA cursorData;
2506c2c66affSColin Finck     HICON hIcon;
2507c2c66affSColin Finck     BOOL isAnimated;
2508c2c66affSColin Finck 
2509c2c66affSColin Finck     TRACE("%p, %lu, %lu, %lu, %i, %i, %lu.\n", pbIconBits, cbIconBits, fIcon, dwVersion, cxDesired, cyDesired, uFlags);
2510c2c66affSColin Finck 
2511c2c66affSColin Finck     if(uFlags & LR_DEFAULTSIZE)
2512c2c66affSColin Finck     {
2513c2c66affSColin Finck         if(!cxDesired) cxDesired = GetSystemMetrics(fIcon ? SM_CXICON : SM_CXCURSOR);
2514c2c66affSColin Finck         if(!cyDesired) cyDesired = GetSystemMetrics(fIcon ? SM_CYICON : SM_CYCURSOR);
2515c2c66affSColin Finck     }
2516c2c66affSColin Finck 
2517c2c66affSColin Finck     ZeroMemory(&cursorData, sizeof(cursorData));
2518c2c66affSColin Finck     cursorData.cx = cxDesired;
2519c2c66affSColin Finck     cursorData.cy = cyDesired;
2520c2c66affSColin Finck     cursorData.rt = (USHORT)((ULONG_PTR)(fIcon ? RT_ICON : RT_CURSOR));
2521c2c66affSColin Finck 
2522c2c66affSColin Finck     /* Convert to win32k-ready data */
2523c2c66affSColin Finck     if(!memcmp(pbIconBits, "RIFF", 4))
2524c2c66affSColin Finck     {
2525c2c66affSColin Finck         if(!CURSORICON_GetCursorDataFromANI(&cursorData, pbIconBits, cbIconBits, uFlags))
2526c2c66affSColin Finck         {
2527c2c66affSColin Finck             ERR("Could not get cursor data from .ani.\n");
2528c2c66affSColin Finck             return NULL;
2529c2c66affSColin Finck         }
2530c2c66affSColin Finck         isAnimated = !!(cursorData.CURSORF_flags & CURSORF_ACON);
2531c2c66affSColin Finck     }
2532c2c66affSColin Finck     else
2533c2c66affSColin Finck     {
2534c2c66affSColin Finck         /* It is possible to pass Icon Directories to this API */
2535c2c66affSColin Finck         int wResId = LookupIconIdFromDirectoryEx(pbIconBits, fIcon, cxDesired, cyDesired, uFlags);
2536c2c66affSColin Finck         HANDLE ResHandle = NULL;
2537a47590c9SDoug Lyons #ifdef __REACTOS__
2538a47590c9SDoug Lyons         if (wResId && (pbIconBits[4] != sizeof(BITMAPINFOHEADER)))
2539a47590c9SDoug Lyons #else
2540c2c66affSColin Finck         if(wResId)
2541a47590c9SDoug Lyons #endif
2542c2c66affSColin Finck         {
2543c2c66affSColin Finck             HINSTANCE hinst;
2544c2c66affSColin Finck             HRSRC hrsrc;
2545c2c66affSColin Finck             CURSORICONDIR* pCurIconDir = (CURSORICONDIR*)pbIconBits;
2546c2c66affSColin Finck 
2547c2c66affSColin Finck             TRACE("Pointer points to a directory structure.\n");
2548c2c66affSColin Finck 
2549c2c66affSColin Finck             /* So this is a pointer to an icon directory structure. Find the module */
2550c2c66affSColin Finck             if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
2551c2c66affSColin Finck                     (LPCWSTR)pbIconBits,
2552c2c66affSColin Finck                     &hinst))
2553c2c66affSColin Finck             {
2554c2c66affSColin Finck                 return NULL;
2555c2c66affSColin Finck             }
2556c2c66affSColin Finck 
2557c2c66affSColin Finck             /* Check we were given the right type of resource */
2558c2c66affSColin Finck             if((fIcon && pCurIconDir->idType == 2) || (!fIcon && pCurIconDir->idType == 1))
2559c2c66affSColin Finck             {
256003422451SSerge Gautherie                 WARN("Got a %s directory pointer, but called for a %s\n", fIcon ? "cursor" : "icon", fIcon ? "icon" : "cursor");
2561c2c66affSColin Finck                 return NULL;
2562c2c66affSColin Finck             }
2563c2c66affSColin Finck 
2564c2c66affSColin Finck             /* Get the relevant resource pointer */
2565c2c66affSColin Finck             hrsrc = FindResourceW(
2566c2c66affSColin Finck                 hinst,
2567c2c66affSColin Finck                 MAKEINTRESOURCEW(wResId),
2568c2c66affSColin Finck                 fIcon ? RT_ICON : RT_CURSOR);
2569c2c66affSColin Finck             if (!hrsrc)
2570c2c66affSColin Finck                 return NULL;
2571c2c66affSColin Finck 
2572c2c66affSColin Finck             ResHandle = LoadResource(hinst, hrsrc);
2573c2c66affSColin Finck             if (!ResHandle)
2574c2c66affSColin Finck                 return NULL;
2575c2c66affSColin Finck 
2576c2c66affSColin Finck             pbIconBits = LockResource(ResHandle);
2577c2c66affSColin Finck             if (!pbIconBits)
2578c2c66affSColin Finck             {
2579c2c66affSColin Finck                 FreeResource(ResHandle);
2580c2c66affSColin Finck                 return NULL;
2581c2c66affSColin Finck             }
2582c2c66affSColin Finck         }
2583c2c66affSColin Finck         if(!fIcon)
2584c2c66affSColin Finck         {
2585c2c66affSColin Finck             WORD* pt = (WORD*)pbIconBits;
2586c2c66affSColin Finck             cursorData.xHotspot = *pt++;
2587c2c66affSColin Finck             cursorData.yHotspot = *pt++;
2588c2c66affSColin Finck             pbIconBits = (PBYTE)pt;
2589c2c66affSColin Finck         }
2590c2c66affSColin Finck 
2591c2c66affSColin Finck         if (!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO*)pbIconBits))
2592c2c66affSColin Finck         {
2593c2c66affSColin Finck             ERR("Couldn't fill the CURSORDATA structure.\n");
2594c2c66affSColin Finck             if (ResHandle)
2595c2c66affSColin Finck                 FreeResource(ResHandle);
2596c2c66affSColin Finck             return NULL;
2597c2c66affSColin Finck         }
2598c2c66affSColin Finck         if (ResHandle)
2599c2c66affSColin Finck             FreeResource(ResHandle);
2600c2c66affSColin Finck         isAnimated = FALSE;
2601c2c66affSColin Finck     }
2602c2c66affSColin Finck 
2603c2c66affSColin Finck     if (uFlags & LR_SHARED)
2604c2c66affSColin Finck         cursorData.CURSORF_flags |= CURSORF_LRSHARED;
2605c2c66affSColin Finck 
2606c2c66affSColin Finck     hIcon = NtUserxCreateEmptyCurObject(isAnimated);
2607c2c66affSColin Finck     if (!hIcon)
2608c2c66affSColin Finck         goto end_error;
2609c2c66affSColin Finck 
2610c2c66affSColin Finck     if(!NtUserSetCursorIconData(hIcon, NULL, NULL, &cursorData))
2611c2c66affSColin Finck     {
2612c2c66affSColin Finck         ERR("NtUserSetCursorIconData failed.\n");
2613c2c66affSColin Finck         NtUserDestroyCursor(hIcon, TRUE);
2614c2c66affSColin Finck         goto end_error;
2615c2c66affSColin Finck     }
2616c2c66affSColin Finck 
2617c2c66affSColin Finck     if(isAnimated)
2618c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, cursorData.aspcur);
2619c2c66affSColin Finck 
2620c2c66affSColin Finck     return hIcon;
2621c2c66affSColin Finck 
2622c2c66affSColin Finck     /* Clean up */
2623c2c66affSColin Finck end_error:
2624c2c66affSColin Finck     if(isAnimated)
2625c2c66affSColin Finck         HeapFree(GetProcessHeap(), 0, cursorData.aspcur);
2626c2c66affSColin Finck     DeleteObject(cursorData.hbmMask);
2627c2c66affSColin Finck     if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor);
2628c2c66affSColin Finck     if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha);
2629c2c66affSColin Finck 
2630c2c66affSColin Finck     return NULL;
2631c2c66affSColin Finck }
2632c2c66affSColin Finck 
CreateIconIndirect(_In_ PICONINFO piconinfo)2633c2c66affSColin Finck HICON WINAPI CreateIconIndirect(
2634c2c66affSColin Finck   _In_  PICONINFO piconinfo
2635c2c66affSColin Finck )
2636c2c66affSColin Finck {
2637c2c66affSColin Finck     /* As simple as creating a handle, and let win32k deal with the bitmaps */
2638c2c66affSColin Finck     HICON hiconRet;
2639c2c66affSColin Finck     CURSORDATA cursorData;
2640c2c66affSColin Finck 
2641c2c66affSColin Finck     TRACE("%p.\n", piconinfo);
2642c2c66affSColin Finck 
2643c2c66affSColin Finck     ZeroMemory(&cursorData, sizeof(cursorData));
2644c2c66affSColin Finck 
2645c2c66affSColin Finck     if(!CURSORICON_GetCursorDataFromIconInfo(&cursorData, piconinfo))
2646c2c66affSColin Finck         return NULL;
2647c2c66affSColin Finck 
2648c2c66affSColin Finck     hiconRet = NtUserxCreateEmptyCurObject(FALSE);
2649c2c66affSColin Finck     if(!hiconRet)
2650c2c66affSColin Finck         goto end_error;
2651c2c66affSColin Finck 
2652c2c66affSColin Finck     if(!NtUserSetCursorIconData(hiconRet, NULL, NULL, &cursorData))
2653c2c66affSColin Finck     {
2654c2c66affSColin Finck         NtUserDestroyCursor(hiconRet, FALSE);
2655c2c66affSColin Finck         goto end_error;
2656c2c66affSColin Finck     }
2657c2c66affSColin Finck 
2658c2c66affSColin Finck     TRACE("Returning 0x%08x.\n", hiconRet);
2659c2c66affSColin Finck 
2660c2c66affSColin Finck     return hiconRet;
2661c2c66affSColin Finck 
2662c2c66affSColin Finck end_error:
2663c2c66affSColin Finck     /* Clean up */
2664c2c66affSColin Finck     DeleteObject(cursorData.hbmMask);
2665c2c66affSColin Finck     if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor);
2666c2c66affSColin Finck     if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha);
2667c2c66affSColin Finck 
2668c2c66affSColin Finck     return NULL;
2669c2c66affSColin Finck }
2670c2c66affSColin Finck 
CreateCursor(_In_opt_ HINSTANCE hInst,_In_ int xHotSpot,_In_ int yHotSpot,_In_ int nWidth,_In_ int nHeight,_In_ const VOID * pvANDPlane,_In_ const VOID * pvXORPlane)2671c2c66affSColin Finck HCURSOR WINAPI CreateCursor(
2672c2c66affSColin Finck   _In_opt_  HINSTANCE hInst,
2673c2c66affSColin Finck   _In_      int xHotSpot,
2674c2c66affSColin Finck   _In_      int yHotSpot,
2675c2c66affSColin Finck   _In_      int nWidth,
2676c2c66affSColin Finck   _In_      int nHeight,
2677c2c66affSColin Finck   _In_      const VOID *pvANDPlane,
2678c2c66affSColin Finck   _In_      const VOID *pvXORPlane
2679c2c66affSColin Finck )
2680c2c66affSColin Finck {
2681c2c66affSColin Finck     ICONINFO info;
2682c2c66affSColin Finck     HCURSOR hCursor;
2683c2c66affSColin Finck 
2684c2c66affSColin Finck     TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
2685c2c66affSColin Finck                     nWidth, nHeight, xHotSpot, yHotSpot, pvXORPlane, pvANDPlane);
2686c2c66affSColin Finck 
2687c2c66affSColin Finck     info.fIcon = FALSE;
2688c2c66affSColin Finck     info.xHotspot = xHotSpot;
2689c2c66affSColin Finck     info.yHotspot = yHotSpot;
2690c2c66affSColin Finck     info.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, pvANDPlane );
2691c2c66affSColin Finck     info.hbmColor = CreateBitmap( nWidth, nHeight, 1, 1, pvXORPlane );
2692c2c66affSColin Finck     hCursor = CreateIconIndirect( &info );
2693c2c66affSColin Finck     DeleteObject( info.hbmMask );
2694c2c66affSColin Finck     DeleteObject( info.hbmColor );
2695c2c66affSColin Finck     return hCursor;
2696c2c66affSColin Finck }
2697c2c66affSColin Finck 
SetSystemCursor(_In_ HCURSOR hcur,_In_ DWORD id)2698c2c66affSColin Finck BOOL WINAPI SetSystemCursor(
2699c2c66affSColin Finck   _In_  HCURSOR hcur,
2700c2c66affSColin Finck   _In_  DWORD id
2701c2c66affSColin Finck )
2702c2c66affSColin Finck {
2703c2c66affSColin Finck     if (hcur == NULL)
2704c2c66affSColin Finck     {
2705345ad553SSerge Gautherie        hcur = LoadImageW(NULL, MAKEINTRESOURCEW(id), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE);
2706c2c66affSColin Finck        if (hcur == NULL)
2707c2c66affSColin Finck        {
2708c2c66affSColin Finck           return FALSE;
2709c2c66affSColin Finck        }
2710c2c66affSColin Finck     }
2711c2c66affSColin Finck     return NtUserSetSystemCursor(hcur,id);
2712c2c66affSColin Finck }
2713c2c66affSColin Finck 
SetCursorPos(_In_ int X,_In_ int Y)2714c2c66affSColin Finck BOOL WINAPI SetCursorPos(
2715c2c66affSColin Finck   _In_  int X,
2716c2c66affSColin Finck   _In_  int Y
2717c2c66affSColin Finck )
2718c2c66affSColin Finck {
2719c2c66affSColin Finck     return NtUserxSetCursorPos(X,Y);
2720c2c66affSColin Finck }
2721c2c66affSColin Finck 
GetCursorPos(_Out_ LPPOINT lpPoint)2722c2c66affSColin Finck BOOL WINAPI GetCursorPos(
2723c2c66affSColin Finck   _Out_  LPPOINT lpPoint
2724c2c66affSColin Finck )
2725c2c66affSColin Finck {
2726c2c66affSColin Finck     return NtUserxGetCursorPos(lpPoint);
2727c2c66affSColin Finck }
2728c2c66affSColin Finck 
ShowCursor(_In_ BOOL bShow)2729c2c66affSColin Finck int WINAPI ShowCursor(
2730c2c66affSColin Finck   _In_  BOOL bShow
2731c2c66affSColin Finck )
2732c2c66affSColin Finck {
2733c2c66affSColin Finck     return NtUserxShowCursor(bShow);
2734c2c66affSColin Finck }
2735c2c66affSColin Finck 
GetCursor(void)2736c2c66affSColin Finck HCURSOR WINAPI GetCursor(void)
2737c2c66affSColin Finck {
2738c2c66affSColin Finck     return (HCURSOR)NtUserGetThreadState(THREADSTATE_GETCURSOR);
2739c2c66affSColin Finck }
2740c2c66affSColin Finck 
DestroyCursor(_In_ HCURSOR hCursor)2741c2c66affSColin Finck BOOL WINAPI DestroyCursor(
2742c2c66affSColin Finck   _In_  HCURSOR hCursor
2743c2c66affSColin Finck )
2744c2c66affSColin Finck {
2745c2c66affSColin Finck     return NtUserDestroyCursor(hCursor, FALSE);
2746c2c66affSColin Finck }
2747c2c66affSColin Finck 
2748c2c66affSColin Finck HCURSOR
2749c2c66affSColin Finck WINAPI
GetCursorFrameInfo(HCURSOR hCursor,DWORD reserved,DWORD istep,PINT rate_jiffies,DWORD * num_steps)2750c2c66affSColin Finck GetCursorFrameInfo(HCURSOR hCursor, DWORD reserved, DWORD istep, PINT rate_jiffies, DWORD *num_steps)
2751c2c66affSColin Finck {
2752c2c66affSColin Finck    return NtUserGetCursorFrameInfo(hCursor, istep, rate_jiffies, num_steps);
2753c2c66affSColin Finck }
2754