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