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