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