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