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