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 HANDLE WINAPI CopyImage( 2019 _In_ HANDLE hImage, 2020 _In_ UINT uType, 2021 _In_ int cxDesired, 2022 _In_ int cyDesired, 2023 _In_ UINT fuFlags 2024 ) 2025 { 2026 TRACE("hImage=%p, uType=%u, cxDesired=%d, cyDesired=%d, fuFlags=%x\n", 2027 hImage, uType, cxDesired, cyDesired, fuFlags); 2028 switch(uType) 2029 { 2030 case IMAGE_BITMAP: 2031 return BITMAP_CopyImage(hImage, cxDesired, cyDesired, fuFlags); 2032 case IMAGE_CURSOR: 2033 case IMAGE_ICON: 2034 return CURSORICON_CopyImage(hImage, uType == IMAGE_ICON, cxDesired, cyDesired, fuFlags); 2035 default: 2036 SetLastError(ERROR_INVALID_PARAMETER); 2037 break; 2038 } 2039 return NULL; 2040 } 2041 2042 HICON WINAPI CopyIcon( 2043 _In_ HICON hIcon 2044 ) 2045 { 2046 return CURSORICON_CopyImage(hIcon, FALSE, 0, 0, 0); 2047 } 2048 2049 BOOL WINAPI DrawIcon( 2050 _In_ HDC hDC, 2051 _In_ int X, 2052 _In_ int Y, 2053 _In_ HICON hIcon 2054 ) 2055 { 2056 return DrawIconEx(hDC, X, Y, hIcon, 0, 0, 0, NULL, DI_NORMAL | DI_COMPAT | DI_DEFAULTSIZE); 2057 } 2058 2059 BOOL WINAPI DrawIconEx( 2060 _In_ HDC hdc, 2061 _In_ int xLeft, 2062 _In_ int yTop, 2063 _In_ HICON hIcon, 2064 _In_ int cxWidth, 2065 _In_ int cyWidth, 2066 _In_ UINT istepIfAniCur, 2067 _In_opt_ HBRUSH hbrFlickerFreeDraw, 2068 _In_ UINT diFlags 2069 ) 2070 { 2071 return NtUserDrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth, 2072 istepIfAniCur, hbrFlickerFreeDraw, diFlags, 2073 0, 0); 2074 } 2075 2076 BOOL WINAPI GetIconInfo( 2077 _In_ HICON hIcon, 2078 _Out_ PICONINFO piconinfo 2079 ) 2080 { 2081 return NtUserGetIconInfo(hIcon, piconinfo, NULL, NULL, NULL, FALSE); 2082 } 2083 2084 BOOL WINAPI DestroyIcon( 2085 _In_ HICON hIcon 2086 ) 2087 { 2088 return NtUserDestroyCursor(hIcon, FALSE); 2089 } 2090 2091 HICON WINAPI LoadIconA( 2092 _In_opt_ HINSTANCE hInstance, 2093 _In_ LPCSTR lpIconName 2094 ) 2095 { 2096 TRACE("%p, %s\n", hInstance, debugstr_a(lpIconName)); 2097 2098 return LoadImageA(hInstance, 2099 lpIconName, 2100 IMAGE_ICON, 2101 0, 2102 0, 2103 LR_SHARED | LR_DEFAULTSIZE ); 2104 } 2105 2106 HICON WINAPI LoadIconW( 2107 _In_opt_ HINSTANCE hInstance, 2108 _In_ LPCWSTR lpIconName 2109 ) 2110 { 2111 TRACE("%p, %s\n", hInstance, debugstr_w(lpIconName)); 2112 2113 return LoadImageW(hInstance, 2114 lpIconName, 2115 IMAGE_ICON, 2116 0, 2117 0, 2118 LR_SHARED | LR_DEFAULTSIZE ); 2119 } 2120 2121 HCURSOR WINAPI LoadCursorA( 2122 _In_opt_ HINSTANCE hInstance, 2123 _In_ LPCSTR lpCursorName 2124 ) 2125 { 2126 TRACE("%p, %s\n", hInstance, debugstr_a(lpCursorName)); 2127 2128 return LoadImageA(hInstance, 2129 lpCursorName, 2130 IMAGE_CURSOR, 2131 0, 2132 0, 2133 LR_SHARED | LR_DEFAULTSIZE ); 2134 } 2135 2136 HCURSOR WINAPI LoadCursorW( 2137 _In_opt_ HINSTANCE hInstance, 2138 _In_ LPCWSTR lpCursorName 2139 ) 2140 { 2141 TRACE("%p, %s\n", hInstance, debugstr_w(lpCursorName)); 2142 2143 return LoadImageW(hInstance, 2144 lpCursorName, 2145 IMAGE_CURSOR, 2146 0, 2147 0, 2148 LR_SHARED | LR_DEFAULTSIZE ); 2149 } 2150 2151 HCURSOR WINAPI LoadCursorFromFileA( 2152 _In_ LPCSTR lpFileName 2153 ) 2154 { 2155 TRACE("%s\n", debugstr_a(lpFileName)); 2156 2157 return LoadImageA(NULL, 2158 lpFileName, 2159 IMAGE_CURSOR, 2160 0, 2161 0, 2162 LR_LOADFROMFILE | LR_DEFAULTSIZE ); 2163 } 2164 2165 HCURSOR WINAPI LoadCursorFromFileW( 2166 _In_ LPCWSTR lpFileName 2167 ) 2168 { 2169 TRACE("%s\n", debugstr_w(lpFileName)); 2170 2171 return LoadImageW(NULL, 2172 lpFileName, 2173 IMAGE_CURSOR, 2174 0, 2175 0, 2176 LR_LOADFROMFILE | LR_DEFAULTSIZE ); 2177 } 2178 2179 HBITMAP WINAPI LoadBitmapA( 2180 _In_opt_ HINSTANCE hInstance, 2181 _In_ LPCSTR lpBitmapName 2182 ) 2183 { 2184 TRACE("%p, %s\n", hInstance, debugstr_a(lpBitmapName)); 2185 2186 return LoadImageA(hInstance, 2187 lpBitmapName, 2188 IMAGE_BITMAP, 2189 0, 2190 0, 2191 0); 2192 } 2193 2194 HBITMAP WINAPI LoadBitmapW( 2195 _In_opt_ HINSTANCE hInstance, 2196 _In_ LPCWSTR lpBitmapName 2197 ) 2198 { 2199 TRACE("%p, %s\n", hInstance, debugstr_w(lpBitmapName)); 2200 2201 return LoadImageW(hInstance, 2202 lpBitmapName, 2203 IMAGE_BITMAP, 2204 0, 2205 0, 2206 0); 2207 } 2208 2209 HANDLE WINAPI LoadImageA( 2210 _In_opt_ HINSTANCE hinst, 2211 _In_ LPCSTR lpszName, 2212 _In_ UINT uType, 2213 _In_ int cxDesired, 2214 _In_ int cyDesired, 2215 _In_ UINT fuLoad 2216 ) 2217 { 2218 HANDLE res; 2219 LPWSTR u_name; 2220 DWORD len; 2221 2222 if (IS_INTRESOURCE(lpszName)) 2223 return LoadImageW(hinst, (LPCWSTR)lpszName, uType, cxDesired, cyDesired, fuLoad); 2224 2225 len = MultiByteToWideChar( CP_ACP, 0, lpszName, -1, NULL, 0 ); 2226 u_name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); 2227 MultiByteToWideChar( CP_ACP, 0, lpszName, -1, u_name, len ); 2228 2229 res = LoadImageW(hinst, u_name, uType, cxDesired, cyDesired, fuLoad); 2230 HeapFree(GetProcessHeap(), 0, u_name); 2231 return res; 2232 } 2233 2234 HANDLE WINAPI LoadImageW( 2235 _In_opt_ HINSTANCE hinst, 2236 _In_ LPCWSTR lpszName, 2237 _In_ UINT uType, 2238 _In_ int cxDesired, 2239 _In_ int cyDesired, 2240 _In_ UINT fuLoad 2241 ) 2242 { 2243 TRACE("hinst 0x%p, name %s, uType 0x%08x, cxDesired %d, cyDesired %d, fuLoad 0x%08x.\n", 2244 hinst, debugstr_w(lpszName), uType, cxDesired, cyDesired, fuLoad); 2245 /* Redirect to each implementation */ 2246 switch(uType) 2247 { 2248 case IMAGE_BITMAP: 2249 return BITMAP_LoadImageW(hinst, lpszName, cxDesired, cyDesired, fuLoad); 2250 case IMAGE_CURSOR: 2251 case IMAGE_ICON: 2252 return CURSORICON_LoadImageW(hinst, lpszName, cxDesired, cyDesired, fuLoad, uType == IMAGE_ICON); 2253 default: 2254 SetLastError(ERROR_INVALID_PARAMETER); 2255 break; 2256 } 2257 return NULL; 2258 } 2259 2260 int WINAPI LookupIconIdFromDirectory( 2261 _In_ PBYTE presbits, 2262 _In_ BOOL fIcon 2263 ) 2264 { 2265 return LookupIconIdFromDirectoryEx( presbits, fIcon, 2266 fIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR), 2267 fIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), fIcon ? 0 : LR_MONOCHROME ); 2268 } 2269 2270 int WINAPI LookupIconIdFromDirectoryEx( 2271 _In_ PBYTE presbits, 2272 _In_ BOOL fIcon, 2273 _In_ int cxDesired, 2274 _In_ int cyDesired, 2275 _In_ UINT Flags 2276 ) 2277 { 2278 WORD bppDesired; 2279 CURSORICONDIR* dir = (CURSORICONDIR*)presbits; 2280 CURSORICONDIRENTRY* entry; 2281 int i, numMatch = 0, iIndex = -1; 2282 WORD width, height, BitCount = 0; 2283 BOOL notPaletted = FALSE; 2284 ULONG bestScore = 0xFFFFFFFF, score; 2285 2286 TRACE("%p, %x, %i, %i, %x.\n", presbits, fIcon, cxDesired, cyDesired, Flags); 2287 2288 if(!(dir && !dir->idReserved && (dir->idType & 3))) 2289 { 2290 WARN("Invalid resource.\n"); 2291 return 0; 2292 } 2293 2294 if(Flags & LR_MONOCHROME) 2295 bppDesired = 1; 2296 else 2297 { 2298 HDC icScreen; 2299 icScreen = CreateICW(DISPLAYW, NULL, NULL, NULL); 2300 if(!icScreen) 2301 return FALSE; 2302 2303 bppDesired = GetDeviceCaps(icScreen, BITSPIXEL); 2304 DeleteDC(icScreen); 2305 } 2306 2307 if(!cxDesired) 2308 cxDesired = Flags & LR_DEFAULTSIZE ? GetSystemMetrics(fIcon ? SM_CXICON : SM_CXCURSOR) : 256; 2309 if(!cyDesired) 2310 cyDesired = Flags & LR_DEFAULTSIZE ? GetSystemMetrics(fIcon ? SM_CYICON : SM_CYCURSOR) : 256; 2311 2312 /* Find the best match for the desired size */ 2313 for(i = 0; i < dir->idCount; i++) 2314 { 2315 entry = &dir->idEntries[i]; 2316 width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth; 2317 /* Height is twice as big in cursor resources */ 2318 height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2; 2319 /* 0 represents 256 */ 2320 if(!width) width = 256; 2321 if(!height) height = 256; 2322 /* Calculate the "score" (lower is better) */ 2323 score = 2*(abs(width - cxDesired) + abs(height - cyDesired)); 2324 if( score > bestScore) 2325 continue; 2326 /* Bigger than requested lowers the score */ 2327 if(width > cxDesired) 2328 score -= width - cxDesired; 2329 if(height > cyDesired) 2330 score -= height - cyDesired; 2331 if(score > bestScore) 2332 continue; 2333 if(score == bestScore) 2334 { 2335 if(entry->wBitCount > BitCount) 2336 BitCount = entry->wBitCount; 2337 numMatch++; 2338 continue; 2339 } 2340 iIndex = i; 2341 numMatch = 1; 2342 bestScore = score; 2343 BitCount = entry->wBitCount; 2344 } 2345 2346 if(numMatch == 1) 2347 { 2348 /* Only one entry fits the asked dimensions */ 2349 return dir->idEntries[iIndex].wResId; 2350 } 2351 2352 /* Avoid paletted icons on non-paletted device */ 2353 if (bppDesired > 8 && BitCount > 8) 2354 notPaletted = TRUE; 2355 2356 BitCount = 0; 2357 iIndex = -1; 2358 /* Now find the entry with the best depth */ 2359 for(i = 0; i < dir->idCount; i++) 2360 { 2361 entry = &dir->idEntries[i]; 2362 width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth; 2363 height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2; 2364 /* 0 represents 256 */ 2365 if(!width) width = 256; 2366 if(!height) height = 256; 2367 /* Check if this is the best match we had */ 2368 score = 2*(abs(width - cxDesired) + abs(height - cyDesired)); 2369 if(width > cxDesired) 2370 score -= width - cxDesired; 2371 if(height > cyDesired) 2372 score -= height - cyDesired; 2373 if(score != bestScore) 2374 continue; 2375 /* Exact match? */ 2376 if(entry->wBitCount == bppDesired) 2377 return entry->wResId; 2378 /* We take the highest possible but smaller than the display depth */ 2379 if((entry->wBitCount > BitCount) && (entry->wBitCount < bppDesired)) 2380 { 2381 /* Avoid paletted icons on non paletted devices */ 2382 if ((entry->wBitCount <= 8) && notPaletted) 2383 continue; 2384 iIndex = i; 2385 BitCount = entry->wBitCount; 2386 } 2387 } 2388 2389 if(iIndex >= 0) 2390 return dir->idEntries[iIndex].wResId; 2391 2392 /* No inferior or equal depth available. Get the smallest bigger one */ 2393 BitCount = 0xFFFF; 2394 iIndex = -1; 2395 for(i = 0; i < dir->idCount; i++) 2396 { 2397 entry = &dir->idEntries[i]; 2398 width = fIcon ? entry->ResInfo.icon.bWidth : entry->ResInfo.cursor.wWidth; 2399 height = fIcon ? entry->ResInfo.icon.bHeight : entry->ResInfo.cursor.wHeight/2; 2400 /* 0 represents 256 */ 2401 if(!width) width = 256; 2402 if(!height) height = 256; 2403 /* Check if this is the best match we had */ 2404 score = 2*(abs(width - cxDesired) + abs(height - cyDesired)); 2405 if(width > cxDesired) 2406 score -= width - cxDesired; 2407 if(height > cyDesired) 2408 score -= height - cyDesired; 2409 if(score != bestScore) 2410 continue; 2411 /* Check the bit depth */ 2412 if(entry->wBitCount < BitCount) 2413 { 2414 if((entry->wBitCount <= 8) && notPaletted) 2415 continue; 2416 iIndex = i; 2417 BitCount = entry->wBitCount; 2418 } 2419 } 2420 if (iIndex >= 0) 2421 return dir->idEntries[iIndex].wResId; 2422 2423 return 0; 2424 } 2425 2426 HICON WINAPI CreateIcon( 2427 _In_opt_ HINSTANCE hInstance, 2428 _In_ int nWidth, 2429 _In_ int nHeight, 2430 _In_ BYTE cPlanes, 2431 _In_ BYTE cBitsPixel, 2432 _In_ const BYTE *lpbANDbits, 2433 _In_ const BYTE *lpbXORbits 2434 ) 2435 { 2436 ICONINFO iinfo; 2437 HICON hIcon; 2438 2439 TRACE_(icon)("%dx%d, planes %d, bpp %d, xor %p, and %p\n", 2440 nWidth, nHeight, cPlanes, cBitsPixel, lpbXORbits, lpbANDbits); 2441 2442 iinfo.fIcon = TRUE; 2443 iinfo.xHotspot = nWidth / 2; 2444 iinfo.yHotspot = nHeight / 2; 2445 if (cPlanes * cBitsPixel > 1) 2446 { 2447 iinfo.hbmColor = CreateBitmap( nWidth, nHeight, cPlanes, cBitsPixel, lpbXORbits ); 2448 iinfo.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpbANDbits ); 2449 } 2450 else 2451 { 2452 iinfo.hbmMask = CreateBitmap( nWidth, nHeight * 2, 1, 1, lpbANDbits ); 2453 iinfo.hbmColor = NULL; 2454 } 2455 2456 hIcon = CreateIconIndirect( &iinfo ); 2457 2458 DeleteObject( iinfo.hbmMask ); 2459 if (iinfo.hbmColor) DeleteObject( iinfo.hbmColor ); 2460 2461 return hIcon; 2462 } 2463 2464 HICON WINAPI CreateIconFromResource( 2465 _In_ PBYTE presbits, 2466 _In_ DWORD dwResSize, 2467 _In_ BOOL fIcon, 2468 _In_ DWORD dwVer 2469 ) 2470 { 2471 return CreateIconFromResourceEx( presbits, dwResSize, fIcon, dwVer, 0, 0, LR_DEFAULTSIZE | LR_SHARED); 2472 } 2473 2474 HICON WINAPI CreateIconFromResourceEx( 2475 _In_ PBYTE pbIconBits, 2476 _In_ DWORD cbIconBits, 2477 _In_ BOOL fIcon, 2478 _In_ DWORD dwVersion, 2479 _In_ int cxDesired, 2480 _In_ int cyDesired, 2481 _In_ UINT uFlags 2482 ) 2483 { 2484 CURSORDATA cursorData; 2485 HICON hIcon; 2486 BOOL isAnimated; 2487 2488 TRACE("%p, %lu, %lu, %lu, %i, %i, %lu.\n", pbIconBits, cbIconBits, fIcon, dwVersion, cxDesired, cyDesired, uFlags); 2489 2490 if(uFlags & LR_DEFAULTSIZE) 2491 { 2492 if(!cxDesired) cxDesired = GetSystemMetrics(fIcon ? SM_CXICON : SM_CXCURSOR); 2493 if(!cyDesired) cyDesired = GetSystemMetrics(fIcon ? SM_CYICON : SM_CYCURSOR); 2494 } 2495 2496 ZeroMemory(&cursorData, sizeof(cursorData)); 2497 cursorData.cx = cxDesired; 2498 cursorData.cy = cyDesired; 2499 cursorData.rt = (USHORT)((ULONG_PTR)(fIcon ? RT_ICON : RT_CURSOR)); 2500 2501 /* Convert to win32k-ready data */ 2502 if(!memcmp(pbIconBits, "RIFF", 4)) 2503 { 2504 if(!CURSORICON_GetCursorDataFromANI(&cursorData, pbIconBits, cbIconBits, uFlags)) 2505 { 2506 ERR("Could not get cursor data from .ani.\n"); 2507 return NULL; 2508 } 2509 isAnimated = !!(cursorData.CURSORF_flags & CURSORF_ACON); 2510 } 2511 else 2512 { 2513 /* It is possible to pass Icon Directories to this API */ 2514 int wResId = LookupIconIdFromDirectoryEx(pbIconBits, fIcon, cxDesired, cyDesired, uFlags); 2515 HANDLE ResHandle = NULL; 2516 #ifdef __REACTOS__ 2517 if (wResId && (pbIconBits[4] != sizeof(BITMAPINFOHEADER))) 2518 #else 2519 if(wResId) 2520 #endif 2521 { 2522 HINSTANCE hinst; 2523 HRSRC hrsrc; 2524 CURSORICONDIR* pCurIconDir = (CURSORICONDIR*)pbIconBits; 2525 2526 TRACE("Pointer points to a directory structure.\n"); 2527 2528 /* So this is a pointer to an icon directory structure. Find the module */ 2529 if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, 2530 (LPCWSTR)pbIconBits, 2531 &hinst)) 2532 { 2533 return NULL; 2534 } 2535 2536 /* Check we were given the right type of resource */ 2537 if((fIcon && pCurIconDir->idType == 2) || (!fIcon && pCurIconDir->idType == 1)) 2538 { 2539 WARN("Got a %s directory pointer, but called for a %s\n", fIcon ? "cursor" : "icon", fIcon ? "icon" : "cursor"); 2540 return NULL; 2541 } 2542 2543 /* Get the relevant resource pointer */ 2544 hrsrc = FindResourceW( 2545 hinst, 2546 MAKEINTRESOURCEW(wResId), 2547 fIcon ? RT_ICON : RT_CURSOR); 2548 if (!hrsrc) 2549 return NULL; 2550 2551 ResHandle = LoadResource(hinst, hrsrc); 2552 if (!ResHandle) 2553 return NULL; 2554 2555 pbIconBits = LockResource(ResHandle); 2556 if (!pbIconBits) 2557 { 2558 FreeResource(ResHandle); 2559 return NULL; 2560 } 2561 } 2562 if(!fIcon) 2563 { 2564 WORD* pt = (WORD*)pbIconBits; 2565 cursorData.xHotspot = *pt++; 2566 cursorData.yHotspot = *pt++; 2567 pbIconBits = (PBYTE)pt; 2568 } 2569 2570 if (!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO*)pbIconBits)) 2571 { 2572 ERR("Couldn't fill the CURSORDATA structure.\n"); 2573 if (ResHandle) 2574 FreeResource(ResHandle); 2575 return NULL; 2576 } 2577 if (ResHandle) 2578 FreeResource(ResHandle); 2579 isAnimated = FALSE; 2580 } 2581 2582 if (uFlags & LR_SHARED) 2583 cursorData.CURSORF_flags |= CURSORF_LRSHARED; 2584 2585 hIcon = NtUserxCreateEmptyCurObject(isAnimated); 2586 if (!hIcon) 2587 goto end_error; 2588 2589 if(!NtUserSetCursorIconData(hIcon, NULL, NULL, &cursorData)) 2590 { 2591 ERR("NtUserSetCursorIconData failed.\n"); 2592 NtUserDestroyCursor(hIcon, TRUE); 2593 goto end_error; 2594 } 2595 2596 if(isAnimated) 2597 HeapFree(GetProcessHeap(), 0, cursorData.aspcur); 2598 2599 return hIcon; 2600 2601 /* Clean up */ 2602 end_error: 2603 if(isAnimated) 2604 HeapFree(GetProcessHeap(), 0, cursorData.aspcur); 2605 DeleteObject(cursorData.hbmMask); 2606 if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor); 2607 if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha); 2608 2609 return NULL; 2610 } 2611 2612 HICON WINAPI CreateIconIndirect( 2613 _In_ PICONINFO piconinfo 2614 ) 2615 { 2616 /* As simple as creating a handle, and let win32k deal with the bitmaps */ 2617 HICON hiconRet; 2618 CURSORDATA cursorData; 2619 2620 TRACE("%p.\n", piconinfo); 2621 2622 ZeroMemory(&cursorData, sizeof(cursorData)); 2623 2624 if(!CURSORICON_GetCursorDataFromIconInfo(&cursorData, piconinfo)) 2625 return NULL; 2626 2627 hiconRet = NtUserxCreateEmptyCurObject(FALSE); 2628 if(!hiconRet) 2629 goto end_error; 2630 2631 if(!NtUserSetCursorIconData(hiconRet, NULL, NULL, &cursorData)) 2632 { 2633 NtUserDestroyCursor(hiconRet, FALSE); 2634 goto end_error; 2635 } 2636 2637 TRACE("Returning 0x%08x.\n", hiconRet); 2638 2639 return hiconRet; 2640 2641 end_error: 2642 /* Clean up */ 2643 DeleteObject(cursorData.hbmMask); 2644 if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor); 2645 if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha); 2646 2647 return NULL; 2648 } 2649 2650 HCURSOR WINAPI CreateCursor( 2651 _In_opt_ HINSTANCE hInst, 2652 _In_ int xHotSpot, 2653 _In_ int yHotSpot, 2654 _In_ int nWidth, 2655 _In_ int nHeight, 2656 _In_ const VOID *pvANDPlane, 2657 _In_ const VOID *pvXORPlane 2658 ) 2659 { 2660 ICONINFO info; 2661 HCURSOR hCursor; 2662 2663 TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n", 2664 nWidth, nHeight, xHotSpot, yHotSpot, pvXORPlane, pvANDPlane); 2665 2666 info.fIcon = FALSE; 2667 info.xHotspot = xHotSpot; 2668 info.yHotspot = yHotSpot; 2669 info.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, pvANDPlane ); 2670 info.hbmColor = CreateBitmap( nWidth, nHeight, 1, 1, pvXORPlane ); 2671 hCursor = CreateIconIndirect( &info ); 2672 DeleteObject( info.hbmMask ); 2673 DeleteObject( info.hbmColor ); 2674 return hCursor; 2675 } 2676 2677 BOOL WINAPI SetSystemCursor( 2678 _In_ HCURSOR hcur, 2679 _In_ DWORD id 2680 ) 2681 { 2682 if (hcur == NULL) 2683 { 2684 hcur = LoadImageW(NULL, MAKEINTRESOURCEW(id), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE); 2685 if (hcur == NULL) 2686 { 2687 return FALSE; 2688 } 2689 } 2690 return NtUserSetSystemCursor(hcur,id); 2691 } 2692 2693 BOOL WINAPI SetCursorPos( 2694 _In_ int X, 2695 _In_ int Y 2696 ) 2697 { 2698 return NtUserxSetCursorPos(X,Y); 2699 } 2700 2701 BOOL WINAPI GetCursorPos( 2702 _Out_ LPPOINT lpPoint 2703 ) 2704 { 2705 return NtUserxGetCursorPos(lpPoint); 2706 } 2707 2708 int WINAPI ShowCursor( 2709 _In_ BOOL bShow 2710 ) 2711 { 2712 return NtUserxShowCursor(bShow); 2713 } 2714 2715 HCURSOR WINAPI GetCursor(void) 2716 { 2717 return (HCURSOR)NtUserGetThreadState(THREADSTATE_GETCURSOR); 2718 } 2719 2720 BOOL WINAPI DestroyCursor( 2721 _In_ HCURSOR hCursor 2722 ) 2723 { 2724 return NtUserDestroyCursor(hCursor, FALSE); 2725 } 2726 2727 HCURSOR 2728 WINAPI 2729 GetCursorFrameInfo(HCURSOR hCursor, DWORD reserved, DWORD istep, PINT rate_jiffies, DWORD *num_steps) 2730 { 2731 return NtUserGetCursorFrameInfo(hCursor, istep, rate_jiffies, num_steps); 2732 } 2733