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