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