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