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 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 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 74 BOOL get_icon_size(HICON hIcon, SIZE *size) 75 { 76 return NtUserGetIconSize(hIcon, 0, &size->cx, &size->cy); 77 } 78 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 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 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 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. */ 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 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 */ 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 */ 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 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* 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 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 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 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 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 */ 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 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 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 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 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 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 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 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 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 2063 HICON WINAPI CopyIcon( 2064 _In_ HICON hIcon 2065 ) 2066 { 2067 return CURSORICON_CopyImage(hIcon, FALSE, 0, 0, 0); 2068 } 2069 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 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 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 2105 BOOL WINAPI DestroyIcon( 2106 _In_ HICON hIcon 2107 ) 2108 { 2109 return NtUserDestroyCursor(hIcon, FALSE); 2110 } 2111 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 2714 BOOL WINAPI SetCursorPos( 2715 _In_ int X, 2716 _In_ int Y 2717 ) 2718 { 2719 return NtUserxSetCursorPos(X,Y); 2720 } 2721 2722 BOOL WINAPI GetCursorPos( 2723 _Out_ LPPOINT lpPoint 2724 ) 2725 { 2726 return NtUserxGetCursorPos(lpPoint); 2727 } 2728 2729 int WINAPI ShowCursor( 2730 _In_ BOOL bShow 2731 ) 2732 { 2733 return NtUserxShowCursor(bShow); 2734 } 2735 2736 HCURSOR WINAPI GetCursor(void) 2737 { 2738 return (HCURSOR)NtUserGetThreadState(THREADSTATE_GETCURSOR); 2739 } 2740 2741 BOOL WINAPI DestroyCursor( 2742 _In_ HCURSOR hCursor 2743 ) 2744 { 2745 return NtUserDestroyCursor(hCursor, FALSE); 2746 } 2747 2748 HCURSOR 2749 WINAPI 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