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