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