cursoricon.c 83.6 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 * Cursor and icon support
 *
 * Copyright 1995 Alexandre Julliard
Alexandre Julliard's avatar
Alexandre Julliard committed
5 6
 *           1996 Martin Von Loewis
 *           1997 Alex Korobka
7
 *           1998 Turchanov Sergey
8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
21
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
 */

/*
 * Theory:
 *
 * Cursors and icons are stored in a global heap block, with the
 * following layout:
 *
 * CURSORICONINFO info;
 * BYTE[]         ANDbits;
 * BYTE[]         XORbits;
 *
 * The bits structures are in the format of a device-dependent bitmap.
 *
 * This layout is very sub-optimal, as the bitmap bits are stored in
 * the X client instead of in the server like other bitmaps; however,
 * some programs (notably Paint Brush) expect to be able to manipulate
 * the bits directly :-(
 */

Steven Edwards's avatar
Steven Edwards committed
42 43 44
#include "config.h"
#include "wine/port.h"

45
#include <stdarg.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
46 47
#include <string.h>
#include <stdlib.h>
48

49
#include "windef.h"
50
#include "winbase.h"
51
#include "wingdi.h"
52
#include "winerror.h"
53
#include "wine/winbase16.h"
54
#include "wine/winuser16.h"
55
#include "wine/exception.h"
56
#include "wine/debug.h"
57
#include "user_private.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
58

59
WINE_DEFAULT_DEBUG_CHANNEL(cursor);
60 61
WINE_DECLARE_DEBUG_CHANNEL(icon);
WINE_DECLARE_DEBUG_CHANNEL(resource);
62

63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
#include "pshpack1.h"

typedef struct {
    BYTE bWidth;
    BYTE bHeight;
    BYTE bColorCount;
    BYTE bReserved;
    WORD xHotspot;
    WORD yHotspot;
    DWORD dwDIBSize;
    DWORD dwDIBOffset;
} CURSORICONFILEDIRENTRY;

typedef struct
{
    WORD                idReserved;
    WORD                idType;
    WORD                idCount;
    CURSORICONFILEDIRENTRY  idEntries[1];
} CURSORICONFILEDIR;

#include "poppack.h"

#define CID_RESOURCE  0x0001
#define CID_WIN32     0x0004
#define CID_NONSHARED 0x0008
89

90
static RECT CURSOR_ClipRect;       /* Cursor clipping rect */
Alexandre Julliard's avatar
Alexandre Julliard committed
91

92
static HDC screen_dc;
93

94 95
static const WCHAR DISPLAYW[] = {'D','I','S','P','L','A','Y',0};

96 97 98 99 100
/**********************************************************************
 * ICONCACHE for cursors/icons loaded with LR_SHARED.
 *
 * FIXME: This should not be allocated on the system heap, but on a
 *        subsystem-global heap (i.e. one for all Win16 processes,
101
 *        and one for each Win32 process).
102 103 104 105 106 107 108
 */
typedef struct tagICONCACHE
{
    struct tagICONCACHE *next;

    HMODULE              hModule;
    HRSRC                hRsrc;
109
    HRSRC                hGroupRsrc;
110
    HICON                hIcon;
111 112 113 114 115 116

    INT                  count;

} ICONCACHE;

static ICONCACHE *IconAnchor = NULL;
117 118 119 120 121 122

static CRITICAL_SECTION IconCrst;
static CRITICAL_SECTION_DEBUG critsect_debug =
{
    0, 0, &IconCrst,
    { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
123
      0, 0, { (DWORD_PTR)(__FILE__ ": IconCrst") }
124 125 126
};
static CRITICAL_SECTION IconCrst = { &critsect_debug, -1, 0, 0, 0, 0 };

127
static const WORD ICON_HOTSPOT = 0x4242;
128

129 130 131 132 133

/***********************************************************************
 *             map_fileW
 *
 * Helper function to map a file to memory:
134
 *  name			-	file name
135
 *  [RETURN] ptr		-	pointer to mapped file
136
 *  [RETURN] filesize           -       pointer size of file to be stored if not NULL
137
 */
138
static void *map_fileW( LPCWSTR name, LPDWORD filesize )
139 140 141 142 143 144 145 146
{
    HANDLE hFile, hMapping;
    LPVOID ptr = NULL;

    hFile = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL,
                         OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0 );
    if (hFile != INVALID_HANDLE_VALUE)
    {
147
        hMapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
148 149 150 151
        if (hMapping)
        {
            ptr = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
            CloseHandle( hMapping );
152 153
            if (filesize)
                *filesize = GetFileSize( hFile, NULL );
154
        }
155
        CloseHandle( hFile );
156 157 158 159 160
    }
    return ptr;
}


161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
/***********************************************************************
 *           get_bitmap_width_bytes
 *
 * Return number of bytes taken by a scanline of 16-bit aligned Windows DDB
 * data.
 */
static int get_bitmap_width_bytes( int width, int bpp )
{
    switch(bpp)
    {
    case 1:
        return 2 * ((width+15) / 16);
    case 4:
        return 2 * ((width+3) / 4);
    case 24:
        width *= 3;
        /* fall through */
    case 8:
        return width + (width & 1);
    case 16:
    case 15:
        return width * 2;
    case 32:
        return width * 4;
    default:
        WARN("Unknown depth %d, please report.\n", bpp );
    }
    return -1;
}


192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
/***********************************************************************
 *          get_dib_width_bytes
 *
 * Return the width of a DIB bitmap in bytes. DIB bitmap data is 32-bit aligned.
 */
static int get_dib_width_bytes( int width, int depth )
{
    int words;

    switch(depth)
    {
    case 1:  words = (width + 31) / 32; break;
    case 4:  words = (width + 7) / 8; break;
    case 8:  words = (width + 3) / 4; break;
    case 15:
    case 16: words = (width + 1) / 2; break;
    case 24: words = (width * 3 + 3)/4; break;
    default:
        WARN("(%d): Unsupported depth\n", depth );
        /* fall through */
    case 32:
        words = width;
    }
    return 4 * words;
}


/***********************************************************************
 *           bitmap_info_size
 *
 * Return the size of the bitmap info structure including color table.
 */
static int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
{
226
    int colors, masks = 0;
227 228 229

    if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
    {
230
        const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
231 232 233 234 235 236 237
        colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
        return sizeof(BITMAPCOREHEADER) + colors *
             ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
    }
    else  /* assume BITMAPINFOHEADER */
    {
        colors = info->bmiHeader.biClrUsed;
238 239
        if (colors > 256) /* buffer overflow otherwise */
                colors = 256;
240 241
        if (!colors && (info->bmiHeader.biBitCount <= 8))
            colors = 1 << info->bmiHeader.biBitCount;
242 243
        if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
        return sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) + colors *
244 245 246 247 248
               ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
    }
}


249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
/***********************************************************************
 *          is_dib_monochrome
 *
 * Returns whether a DIB can be converted to a monochrome DDB.
 *
 * A DIB can be converted if its color table contains only black and
 * white. Black must be the first color in the color table.
 *
 * Note : If the first color in the color table is white followed by
 *        black, we can't convert it to a monochrome DDB with
 *        SetDIBits, because black and white would be inverted.
 */
static BOOL is_dib_monochrome( const BITMAPINFO* info )
{
    if (info->bmiHeader.biBitCount != 1) return FALSE;

    if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
    {
267
        const RGBTRIPLE *rgb = ((const BITMAPCOREINFO*)info)->bmciColors;
268

269 270 271 272 273 274 275 276 277 278 279 280 281
        /* Check if the first color is black */
        if ((rgb->rgbtRed == 0) && (rgb->rgbtGreen == 0) && (rgb->rgbtBlue == 0))
        {
            rgb++;

            /* Check if the second color is white */
            return ((rgb->rgbtRed == 0xff) && (rgb->rgbtGreen == 0xff)
                 && (rgb->rgbtBlue == 0xff));
        }
        else return FALSE;
    }
    else  /* assume BITMAPINFOHEADER */
    {
Eric Pouech's avatar
Eric Pouech committed
282
        const RGBQUAD *rgb = info->bmiColors;
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297

        /* Check if the first color is black */
        if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) &&
            (rgb->rgbBlue == 0) && (rgb->rgbReserved == 0))
        {
            rgb++;

            /* Check if the second color is white */
            return ((rgb->rgbRed == 0xff) && (rgb->rgbGreen == 0xff)
                 && (rgb->rgbBlue == 0xff) && (rgb->rgbReserved == 0));
        }
        else return FALSE;
    }
}

298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
/***********************************************************************
 *           DIB_GetBitmapInfo
 *
 * Get the info from a bitmap header.
 * Return 1 for INFOHEADER, 0 for COREHEADER,
 * 4 for V4HEADER, 5 for V5HEADER, -1 for error.
 */
static int DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width,
                              LONG *height, WORD *bpp, DWORD *compr )
{
    if (header->biSize == sizeof(BITMAPINFOHEADER))
    {
        *width  = header->biWidth;
        *height = header->biHeight;
        *bpp    = header->biBitCount;
        *compr  = header->biCompression;
        return 1;
    }
    if (header->biSize == sizeof(BITMAPCOREHEADER))
    {
318
        const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header;
319 320 321 322 323 324 325 326
        *width  = core->bcWidth;
        *height = core->bcHeight;
        *bpp    = core->bcBitCount;
        *compr  = 0;
        return 0;
    }
    if (header->biSize == sizeof(BITMAPV4HEADER))
    {
327
        const BITMAPV4HEADER *v4hdr = (const BITMAPV4HEADER *)header;
328 329 330 331 332 333 334 335
        *width  = v4hdr->bV4Width;
        *height = v4hdr->bV4Height;
        *bpp    = v4hdr->bV4BitCount;
        *compr  = v4hdr->bV4V4Compression;
        return 4;
    }
    if (header->biSize == sizeof(BITMAPV5HEADER))
    {
336
        const BITMAPV5HEADER *v5hdr = (const BITMAPV5HEADER *)header;
337 338 339 340 341 342
        *width  = v5hdr->bV5Width;
        *height = v5hdr->bV5Height;
        *bpp    = v5hdr->bV5BitCount;
        *compr  = v5hdr->bV5Compression;
        return 5;
    }
343
    ERR("(%d): unknown/wrong size for header\n", header->biSize );
344 345
    return -1;
}
346

347 348 349
/**********************************************************************
 *	    CURSORICON_FindSharedIcon
 */
350
static HICON CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
351
{
352
    HICON hIcon = 0;
353 354 355 356 357 358 359 360
    ICONCACHE *ptr;

    EnterCriticalSection( &IconCrst );

    for ( ptr = IconAnchor; ptr; ptr = ptr->next )
        if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
        {
            ptr->count++;
361
            hIcon = ptr->hIcon;
362 363 364 365 366
            break;
        }

    LeaveCriticalSection( &IconCrst );

367
    return hIcon;
368 369
}

370
/*************************************************************************
371
 * CURSORICON_FindCache
372
 *
Andreas Mohr's avatar
Andreas Mohr committed
373
 * Given a handle, find the corresponding cache element
374 375
 *
 * PARAMS
376
 *      Handle     [I] handle to an Image
377 378 379 380 381 382
 *
 * RETURNS
 *     Success: The cache entry
 *     Failure: NULL
 *
 */
383
static ICONCACHE* CURSORICON_FindCache(HICON hIcon)
384 385 386 387 388 389 390
{
    ICONCACHE *ptr;
    ICONCACHE *pRet=NULL;
    BOOL IsFound = FALSE;

    EnterCriticalSection( &IconCrst );

391
    for (ptr = IconAnchor; ptr != NULL && !IsFound; ptr = ptr->next)
392
    {
393
        if ( hIcon == ptr->hIcon )
394 395 396 397 398 399 400 401 402 403 404
        {
            IsFound = TRUE;
            pRet = ptr;
        }
    }

    LeaveCriticalSection( &IconCrst );

    return pRet;
}

405 406 407
/**********************************************************************
 *	    CURSORICON_AddSharedIcon
 */
408
static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HRSRC hGroupRsrc, HICON hIcon )
409
{
410
    ICONCACHE *ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(ICONCACHE) );
411 412 413 414
    if ( !ptr ) return;

    ptr->hModule = hModule;
    ptr->hRsrc   = hRsrc;
415
    ptr->hIcon  = hIcon;
416
    ptr->hGroupRsrc = hGroupRsrc;
417 418 419 420 421 422 423 424 425 426 427
    ptr->count   = 1;

    EnterCriticalSection( &IconCrst );
    ptr->next    = IconAnchor;
    IconAnchor   = ptr;
    LeaveCriticalSection( &IconCrst );
}

/**********************************************************************
 *	    CURSORICON_DelSharedIcon
 */
428
static INT CURSORICON_DelSharedIcon( HICON hIcon )
429 430 431 432 433 434 435
{
    INT count = -1;
    ICONCACHE *ptr;

    EnterCriticalSection( &IconCrst );

    for ( ptr = IconAnchor; ptr; ptr = ptr->next )
436
        if ( ptr->hIcon == hIcon )
437 438 439 440 441 442 443 444 445 446 447 448 449 450
        {
            if ( ptr->count > 0 ) ptr->count--;
            count = ptr->count;
            break;
        }

    LeaveCriticalSection( &IconCrst );

    return count;
}

/**********************************************************************
 *	    CURSORICON_FreeModuleIcons
 */
451
void CURSORICON_FreeModuleIcons( HMODULE16 hMod16 )
452 453
{
    ICONCACHE **ptr = &IconAnchor;
454
    HMODULE hModule = HMODULE_32(GetExePtr( hMod16 ));
455 456 457 458 459 460 461 462 463

    EnterCriticalSection( &IconCrst );

    while ( *ptr )
    {
        if ( (*ptr)->hModule == hModule )
        {
            ICONCACHE *freePtr = *ptr;
            *ptr = freePtr->next;
464

465
            GlobalFree16(HICON_16(freePtr->hIcon));
466
            HeapFree( GetProcessHeap(), 0, freePtr );
467 468 469 470 471 472 473 474
            continue;
        }
        ptr = &(*ptr)->next;
    }

    LeaveCriticalSection( &IconCrst );
}

475 476 477 478 479 480 481
/*
 *  The following macro functions account for the irregularities of
 *   accessing cursor and icon resources in files and resource entries.
 */
typedef BOOL (*fnGetCIEntry)( LPVOID dir, int n,
                              int *width, int *height, int *bits );

Alexandre Julliard's avatar
Alexandre Julliard committed
482 483 484 485 486
/**********************************************************************
 *	    CURSORICON_FindBestIcon
 *
 * Find the icon closest to the requested size and number of colors.
 */
487 488
static int CURSORICON_FindBestIcon( LPVOID dir, fnGetCIEntry get_entry,
                                    int width, int height, int colors )
Alexandre Julliard's avatar
Alexandre Julliard committed
489
{
490
    int i, cx, cy, bits, bestEntry = -1;
491 492
    UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
    UINT iTempXDiff, iTempYDiff, iTempColorDiff;
Alexandre Julliard's avatar
Alexandre Julliard committed
493

494 495 496
    /* Find Best Fit */
    iTotalDiff = 0xFFFFFFFF;
    iColorDiff = 0xFFFFFFFF;
497
    for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
498
    {
499 500
        iTempXDiff = abs(width - cx);
        iTempYDiff = abs(height - cy);
Alexandre Julliard's avatar
Alexandre Julliard committed
501

502
        if(iTotalDiff > (iTempXDiff + iTempYDiff))
Alexandre Julliard's avatar
Alexandre Julliard committed
503
        {
504 505
            iXDiff = iTempXDiff;
            iYDiff = iTempYDiff;
506
            iTotalDiff = iXDiff + iYDiff;
Alexandre Julliard's avatar
Alexandre Julliard committed
507
        }
508
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
509

510
    /* Find Best Colors for Best Fit */
511
    for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
512
    {
513
        if(abs(width - cx) == iXDiff && abs(height - cy) == iYDiff)
Alexandre Julliard's avatar
Alexandre Julliard committed
514
        {
515
            iTempColorDiff = abs(colors - (1<<bits));
516
            if(iColorDiff > iTempColorDiff)
517
            {
518
                bestEntry = i;
519
                iColorDiff = iTempColorDiff;
520
            }
521 522
        }
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
523 524 525 526

    return bestEntry;
}

527 528 529 530 531 532 533 534 535 536
static BOOL CURSORICON_GetResIconEntry( LPVOID dir, int n,
                                        int *width, int *height, int *bits )
{
    CURSORICONDIR *resdir = dir;
    ICONRESDIR *icon;

    if ( resdir->idCount <= n )
        return FALSE;
    icon = &resdir->idEntries[n].ResInfo.icon;
    *width = icon->bWidth;
537
    *height = icon->bHeight;
538 539 540
    *bits = resdir->idEntries[n].wBitCount;
    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
541 542 543 544 545

/**********************************************************************
 *	    CURSORICON_FindBestCursor
 *
 * Find the cursor closest to the requested size.
546 547
 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
 *        ignored too
Alexandre Julliard's avatar
Alexandre Julliard committed
548
 */
549 550
static int CURSORICON_FindBestCursor( LPVOID dir, fnGetCIEntry get_entry,
                                      int width, int height, int color )
Alexandre Julliard's avatar
Alexandre Julliard committed
551
{
552
    int i, maxwidth, maxheight, cx, cy, bits, bestEntry = -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
553

554 555 556 557
    /* Double height to account for AND and XOR masks */

    height *= 2;

Alexandre Julliard's avatar
Alexandre Julliard committed
558 559 560
    /* First find the largest one smaller than or equal to the requested size*/

    maxwidth = maxheight = 0;
561 562 563 564 565
    for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
    {
        if ((cx <= width) && (cy <= height) &&
            (cx > maxwidth) && (cy > maxheight) &&
            (bits == 1))
Alexandre Julliard's avatar
Alexandre Julliard committed
566
        {
567 568 569
            bestEntry = i;
            maxwidth  = cx;
            maxheight = cy;
Alexandre Julliard's avatar
Alexandre Julliard committed
570
        }
571 572
    }
    if (bestEntry != -1) return bestEntry;
Alexandre Julliard's avatar
Alexandre Julliard committed
573 574 575 576

    /* Now find the smallest one larger than the requested size */

    maxwidth = maxheight = 255;
577 578
    for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
    {
579 580
        if (((cx < maxwidth) && (cy < maxheight) && (bits == 1)) ||
            (bestEntry==-1))
Alexandre Julliard's avatar
Alexandre Julliard committed
581
        {
582 583 584
            bestEntry = i;
            maxwidth  = cx;
            maxheight = cy;
Alexandre Julliard's avatar
Alexandre Julliard committed
585
        }
586
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
587 588 589 590

    return bestEntry;
}

591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
static BOOL CURSORICON_GetResCursorEntry( LPVOID dir, int n,
                                          int *width, int *height, int *bits )
{
    CURSORICONDIR *resdir = dir;
    CURSORDIR *cursor;

    if ( resdir->idCount <= n )
        return FALSE;
    cursor = &resdir->idEntries[n].ResInfo.cursor;
    *width = cursor->wWidth;
    *height = cursor->wHeight;
    *bits = resdir->idEntries[n].wBitCount;
    return TRUE;
}

static CURSORICONDIRENTRY *CURSORICON_FindBestIconRes( CURSORICONDIR * dir,
                                      int width, int height, int colors )
{
    int n;

    n = CURSORICON_FindBestIcon( dir, CURSORICON_GetResIconEntry,
                                 width, height, colors );
    if ( n < 0 )
        return NULL;
    return &dir->idEntries[n];
}

static CURSORICONDIRENTRY *CURSORICON_FindBestCursorRes( CURSORICONDIR *dir,
                                      int width, int height, int color )
{
    int n = CURSORICON_FindBestCursor( dir, CURSORICON_GetResCursorEntry,
                                   width, height, color );
    if ( n < 0 )
        return NULL;
    return &dir->idEntries[n];
}

628 629
static BOOL CURSORICON_GetFileEntry( LPVOID dir, int n,
                                     int *width, int *height, int *bits )
630
{
631 632
    CURSORICONFILEDIR *filedir = dir;
    CURSORICONFILEDIRENTRY *entry;
633

634 635 636 637 638 639
    if ( filedir->idCount <= n )
        return FALSE;
    entry = &filedir->idEntries[n];
    *width = entry->bWidth;
    *height = entry->bHeight;
    *bits = entry->bColorCount;
640
    return TRUE;
641
}
Alexandre Julliard's avatar
Alexandre Julliard committed
642

643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
static CURSORICONFILEDIRENTRY *CURSORICON_FindBestCursorFile( CURSORICONFILEDIR *dir,
                                      int width, int height, int color )
{
    int n = CURSORICON_FindBestCursor( dir, CURSORICON_GetFileEntry,
                                       width, height, color );
    if ( n < 0 )
        return NULL;
    return &dir->idEntries[n];
}

static CURSORICONFILEDIRENTRY *CURSORICON_FindBestIconFile( CURSORICONFILEDIR *dir,
                                      int width, int height, int color )
{
    int n = CURSORICON_FindBestIcon( dir, CURSORICON_GetFileEntry,
                                     width, height, color );
    if ( n < 0 )
        return NULL;
    return &dir->idEntries[n];
}
Alexandre Julliard's avatar
Alexandre Julliard committed
662

663 664 665 666 667
static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
					   POINT16 hotspot, BOOL bIcon,
					   DWORD dwVersion,
					   INT width, INT height,
					   UINT cFlag )
Alexandre Julliard's avatar
Alexandre Julliard committed
668
{
669
    HGLOBAL16 hObj;
670
    static HDC hdcMem;
Alexandre Julliard's avatar
Alexandre Julliard committed
671
    int sizeAnd, sizeXor;
672
    HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
673
    BITMAP bmpXor, bmpAnd;
674 675
    BOOL DoStretch;
    INT size;
Alexandre Julliard's avatar
Alexandre Julliard committed
676

Alexandre Julliard's avatar
Alexandre Julliard committed
677 678
    if (dwVersion == 0x00020000)
    {
679 680
        FIXME_(cursor)("\t2.xx resources are not supported\n");
        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
681 682
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
683
    /* Check bitmap header */
Alexandre Julliard's avatar
Alexandre Julliard committed
684

Alexandre Julliard's avatar
Alexandre Julliard committed
685
    if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
686 687
         (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)  ||
          bmi->bmiHeader.biCompression != BI_RGB) )
Alexandre Julliard's avatar
Alexandre Julliard committed
688
    {
689
          WARN_(cursor)("\tinvalid resource bitmap header.\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
690
          return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
691 692
    }

693 694 695 696 697 698 699
    size = bitmap_info_size( bmi, DIB_RGB_COLORS );

    if (!width) width = bmi->bmiHeader.biWidth;
    if (!height) height = bmi->bmiHeader.biHeight/2;
    DoStretch = (bmi->bmiHeader.biHeight/2 != height) ||
      (bmi->bmiHeader.biWidth != width);

700
    if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
701
    if (screen_dc)
Alexandre Julliard's avatar
Alexandre Julliard committed
702
    {
703
        BITMAPINFO* pInfo;
Alexandre Julliard's avatar
Alexandre Julliard committed
704 705

        /* Make sure we have room for the monochrome bitmap later on.
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
         * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
         * up to and including the biBitCount. In-memory icon resource
         * format is as follows:
         *
         *   BITMAPINFOHEADER   icHeader  // DIB header
         *   RGBQUAD         icColors[]   // Color table
         *   BYTE            icXOR[]      // DIB bits for XOR mask
         *   BYTE            icAND[]      // DIB bits for AND mask
         */

        if ((pInfo = HeapAlloc( GetProcessHeap(), 0,
                                max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))))
        {
            memcpy( pInfo, bmi, size );
            pInfo->bmiHeader.biHeight /= 2;

            /* Create the XOR bitmap */

            if (DoStretch) {
725 726
                if(bIcon)
                {
727
                    hXorBits = CreateCompatibleBitmap(screen_dc, width, height);
728 729 730 731 732 733 734
                }
                else
                {
                    hXorBits = CreateBitmap(width, height, 1, 1, NULL);
                }
                if(hXorBits)
                {
735
                HBITMAP hOld;
736 737 738 739 740 741 742 743 744 745
                BOOL res = FALSE;

                if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
                if (hdcMem) {
                    hOld = SelectObject(hdcMem, hXorBits);
                    res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
                                        bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2,
                                        (char*)bmi + size, pInfo, DIB_RGB_COLORS, SRCCOPY);
                    SelectObject(hdcMem, hOld);
                }
746 747 748
                if (!res) { DeleteObject(hXorBits); hXorBits = 0; }
              }
            } else {
749 750 751 752 753
              if (is_dib_monochrome(bmi)) {
                  hXorBits = CreateBitmap(width, height, 1, 1, NULL);
                  SetDIBits(screen_dc, hXorBits, 0, height,
                     (char*)bmi + size, pInfo, DIB_RGB_COLORS);
              }
754
              else
755 756
                  hXorBits = CreateDIBitmap(screen_dc, &pInfo->bmiHeader,
                     CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS); 
757
            }
758

759 760 761
            if( hXorBits )
            {
                char* xbits = (char *)bmi + size +
762 763
                    get_dib_width_bytes( bmi->bmiHeader.biWidth,
                                         bmi->bmiHeader.biBitCount ) * abs( bmi->bmiHeader.biHeight ) / 2;
Alexandre Julliard's avatar
Alexandre Julliard committed
764

765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787
                pInfo->bmiHeader.biBitCount = 1;
                if (pInfo->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
                {
                    RGBQUAD *rgb = pInfo->bmiColors;

                    pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
                    rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
                    rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
                    rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
                }
                else
                {
                    RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);

                    rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
                    rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
                }

                /* Create the AND bitmap */

            if (DoStretch) {
              if ((hAndBits = CreateBitmap(width, height, 1, 1, NULL))) {
                HBITMAP hOld;
788 789 790 791 792 793 794 795 796 797
                BOOL res = FALSE;

                if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
                if (hdcMem) {
                    hOld = SelectObject(hdcMem, hAndBits);
                    res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
                                        pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight,
                                        xbits, pInfo, DIB_RGB_COLORS, SRCCOPY);
                    SelectObject(hdcMem, hOld);
                }
798 799 800
                if (!res) { DeleteObject(hAndBits); hAndBits = 0; }
              }
            } else {
801
              hAndBits = CreateBitmap(width, height, 1, 1, NULL);
802

803 804
              if (hAndBits) SetDIBits(screen_dc, hAndBits, 0, height,
                             xbits, pInfo, DIB_RGB_COLORS);
805

806 807 808 809 810
            }
                if( !hAndBits ) DeleteObject( hXorBits );
            }
            HeapFree( GetProcessHeap(), 0, pInfo );
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
811
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
812

813
    if( !hXorBits || !hAndBits )
Alexandre Julliard's avatar
Alexandre Julliard committed
814
    {
815 816
        WARN_(cursor)("\tunable to create an icon bitmap.\n");
        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
817
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
818 819

    /* Now create the CURSORICONINFO structure */
820 821 822 823
    GetObjectA( hXorBits, sizeof(bmpXor), &bmpXor );
    GetObjectA( hAndBits, sizeof(bmpAnd), &bmpAnd );
    sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
    sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
Alexandre Julliard's avatar
Alexandre Julliard committed
824

825
    hObj = GlobalAlloc16( GMEM_MOVEABLE,
826
                     sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
827
    if (hObj)
Alexandre Julliard's avatar
Alexandre Julliard committed
828
    {
829
        CURSORICONINFO *info;
Alexandre Julliard's avatar
Alexandre Julliard committed
830

831 832 833 834 835 836 837 838
        info = (CURSORICONINFO *)GlobalLock16( hObj );
        info->ptHotSpot.x   = hotspot.x;
        info->ptHotSpot.y   = hotspot.y;
        info->nWidth        = bmpXor.bmWidth;
        info->nHeight       = bmpXor.bmHeight;
        info->nWidthBytes   = bmpXor.bmWidthBytes;
        info->bPlanes       = bmpXor.bmPlanes;
        info->bBitsPerPixel = bmpXor.bmBitsPixel;
Alexandre Julliard's avatar
Alexandre Julliard committed
839

840
        /* Transfer the bitmap bits to the CURSORICONINFO structure */
Alexandre Julliard's avatar
Alexandre Julliard committed
841

842 843 844
        GetBitmapBits( hAndBits, sizeAnd, (char *)(info + 1) );
        GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
        GlobalUnlock16( hObj );
Alexandre Julliard's avatar
Alexandre Julliard committed
845
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
846

847
    DeleteObject( hAndBits );
848
    DeleteObject( hXorBits );
849
    return HICON_32(hObj);
Alexandre Julliard's avatar
Alexandre Julliard committed
850 851 852
}


853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887
/**********************************************************************
 *		CreateIconFromResourceEx (USER32.@)
 *
 * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
 *        with cbSize parameter as well.
 */
HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
                                       BOOL bIcon, DWORD dwVersion,
                                       INT width, INT height,
                                       UINT cFlag )
{
    POINT16 hotspot;
    BITMAPINFO *bmi;

    hotspot.x = ICON_HOTSPOT;
    hotspot.y = ICON_HOTSPOT;

    TRACE_(cursor)("%p (%u bytes), ver %08x, %ix%i %s %s\n",
                   bits, cbSize, dwVersion, width, height,
                                  bIcon ? "icon" : "cursor", (cFlag & LR_MONOCHROME) ? "mono" : "" );

    if (bIcon)
        bmi = (BITMAPINFO *)bits;
    else /* get the hotspot */
    {
        POINT16 *pt = (POINT16 *)bits;
        hotspot = *pt;
        bmi = (BITMAPINFO *)(pt + 1);
    }

    return CURSORICON_CreateIconFromBMI( bmi, hotspot, bIcon, dwVersion,
					 width, height, cFlag );
}


Alexandre Julliard's avatar
Alexandre Julliard committed
888
/**********************************************************************
889
 *		CreateIconFromResource (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
890
 */
891 892
HICON WINAPI CreateIconFromResource( LPBYTE bits, UINT cbSize,
                                           BOOL bIcon, DWORD dwVersion)
Alexandre Julliard's avatar
Alexandre Julliard committed
893
{
894
    return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
Alexandre Julliard's avatar
Alexandre Julliard committed
895 896 897
}


898 899 900 901 902 903 904 905 906
static HICON CURSORICON_LoadFromFile( LPCWSTR filename,
                             INT width, INT height, INT colors,
                             BOOL fCursor, UINT loadflags)
{
    CURSORICONFILEDIRENTRY *entry;
    CURSORICONFILEDIR *dir;
    DWORD filesize = 0;
    HICON hIcon = 0;
    LPBYTE bits;
907
    POINT16 hotspot;
908 909 910 911 912 913 914

    TRACE("loading %s\n", debugstr_w( filename ));

    bits = map_fileW( filename, &filesize );
    if (!bits)
        return hIcon;

915 916 917 918 919 920 921
    /* Check for .ani. */
    if (memcmp( bits, "RIFF", 4 ) == 0)
    {
        FIXME("No support for .ani cursors.\n");
        goto end;
    }

922 923 924 925 926 927 928 929
    dir = (CURSORICONFILEDIR*) bits;
    if ( filesize < sizeof(*dir) )
        goto end;

    if ( filesize < (sizeof(*dir) + sizeof(dir->idEntries[0])*(dir->idCount-1)) )
        goto end;

    if ( fCursor )
930
        entry = CURSORICON_FindBestCursorFile( dir, width, height, colors );
931 932 933 934 935 936 937 938 939 940 941 942
    else
        entry = CURSORICON_FindBestIconFile( dir, width, height, colors );

    if ( !entry )
        goto end;

    /* check that we don't run off the end of the file */
    if ( entry->dwDIBOffset > filesize )
        goto end;
    if ( entry->dwDIBOffset + entry->dwDIBSize > filesize )
        goto end;

943 944 945 946 947
    hotspot.x = entry->xHotspot;
    hotspot.y = entry->yHotspot;
    hIcon = CURSORICON_CreateIconFromBMI( (BITMAPINFO *)&bits[entry->dwDIBOffset],
					  hotspot, !fCursor, 0x00030000,
					  width, height, loadflags );
948 949 950 951 952 953
end:
    TRACE("loaded %s -> %p\n", debugstr_w( filename ), hIcon );
    UnmapViewOfFile( bits );
    return hIcon;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
954
/**********************************************************************
955
 *          CURSORICON_Load
Alexandre Julliard's avatar
Alexandre Julliard committed
956
 *
957
 * Load a cursor or icon from resource or file.
Alexandre Julliard's avatar
Alexandre Julliard committed
958
 */
959
static HICON CURSORICON_Load(HINSTANCE hInstance, LPCWSTR name,
960 961
                             INT width, INT height, INT colors,
                             BOOL fCursor, UINT loadflags)
Alexandre Julliard's avatar
Alexandre Julliard committed
962
{
963 964
    HANDLE handle = 0;
    HICON hIcon = 0;
965
    HRSRC hRsrc, hGroupRsrc;
966 967 968
    CURSORICONDIR *dir;
    CURSORICONDIRENTRY *dirEntry;
    LPBYTE bits;
969 970
    WORD wResId;
    DWORD dwBytesInRes;
971

972 973 974
    TRACE("%p, %s, %dx%d, colors %d, fCursor %d, flags 0x%04x\n",
          hInstance, debugstr_w(name), width, height, colors, fCursor, loadflags);

975
    if ( loadflags & LR_LOADFROMFILE )    /* Load from file */
976
        return CURSORICON_LoadFromFile( name, width, height, colors, fCursor, loadflags );
Alexandre Julliard's avatar
Alexandre Julliard committed
977

978
    if (!hInstance) hInstance = user32_module;  /* Load OEM cursor/icon */
979

980
    /* Normalize hInstance (must be uniquely represented for icon cache) */
981

982 983
    if (!HIWORD( hInstance ))
        hInstance = HINSTANCE_32(GetExePtr( HINSTANCE_16(hInstance) ));
Alexandre Julliard's avatar
Alexandre Julliard committed
984

985
    /* Get directory resource ID */
Alexandre Julliard's avatar
Alexandre Julliard committed
986

987 988 989 990
    if (!(hRsrc = FindResourceW( hInstance, name,
                                 (LPWSTR)(fCursor ? RT_GROUP_CURSOR : RT_GROUP_ICON) )))
        return 0;
    hGroupRsrc = hRsrc;
Alexandre Julliard's avatar
Alexandre Julliard committed
991

992
    /* Find the best entry in the directory */
993

994 995 996 997 998 999 1000 1001 1002 1003
    if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
    if (!(dir = (CURSORICONDIR*)LockResource( handle ))) return 0;
    if (fCursor)
        dirEntry = CURSORICON_FindBestCursorRes( dir, width, height, 1);
    else
        dirEntry = CURSORICON_FindBestIconRes( dir, width, height, colors );
    if (!dirEntry) return 0;
    wResId = dirEntry->wResId;
    dwBytesInRes = dirEntry->dwBytesInRes;
    FreeResource( handle );
1004

1005
    /* Load the resource */
1006

1007 1008
    if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
                                (LPWSTR)(fCursor ? RT_CURSOR : RT_ICON) ))) return 0;
1009

1010 1011 1012 1013
    /* If shared icon, check whether it was already loaded */
    if (    (loadflags & LR_SHARED)
         && (hIcon = CURSORICON_FindSharedIcon( hInstance, hRsrc ) ) != 0 )
        return hIcon;
1014

1015 1016 1017 1018 1019
    if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
    bits = (LPBYTE)LockResource( handle );
    hIcon = CreateIconFromResourceEx( bits, dwBytesInRes,
                                      !fCursor, 0x00030000, width, height, loadflags);
    FreeResource( handle );
1020

1021
    /* If shared icon, add to icon cache */
1022

1023 1024
    if ( hIcon && (loadflags & LR_SHARED) )
        CURSORICON_AddSharedIcon( hInstance, hRsrc, hGroupRsrc, hIcon );
1025

1026
    return hIcon;
Alexandre Julliard's avatar
Alexandre Julliard committed
1027 1028
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1029 1030 1031 1032 1033
/***********************************************************************
 *           CURSORICON_Copy
 *
 * Make a copy of a cursor or icon.
 */
1034
static HICON CURSORICON_Copy( HINSTANCE16 hInst16, HICON hIcon )
Alexandre Julliard's avatar
Alexandre Julliard committed
1035 1036 1037
{
    char *ptrOld, *ptrNew;
    int size;
1038 1039
    HICON16 hOld = HICON_16(hIcon);
    HICON16 hNew;
Alexandre Julliard's avatar
Alexandre Julliard committed
1040

1041 1042 1043
    if (!(ptrOld = (char *)GlobalLock16( hOld ))) return 0;
    if (hInst16 && !(hInst16 = GetExePtr( hInst16 ))) return 0;
    size = GlobalSize16( hOld );
Alexandre Julliard's avatar
Alexandre Julliard committed
1044
    hNew = GlobalAlloc16( GMEM_MOVEABLE, size );
1045
    FarSetOwner16( hNew, hInst16 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1046
    ptrNew = (char *)GlobalLock16( hNew );
Alexandre Julliard's avatar
Alexandre Julliard committed
1047
    memcpy( ptrNew, ptrOld, size );
1048
    GlobalUnlock16( hOld );
Alexandre Julliard's avatar
Alexandre Julliard committed
1049
    GlobalUnlock16( hNew );
1050
    return HICON_32(hNew);
Alexandre Julliard's avatar
Alexandre Julliard committed
1051 1052
}

1053
/*************************************************************************
1054
 * CURSORICON_ExtCopy
1055 1056 1057 1058
 *
 * Copies an Image from the Cache if LR_COPYFROMRESOURCE is specified
 *
 * PARAMS
1059
 *      Handle     [I] handle to an Image
1060 1061 1062 1063 1064 1065 1066 1067 1068 1069
 *      nType      [I] Type of Handle (IMAGE_CURSOR | IMAGE_ICON)
 *      iDesiredCX [I] The Desired width of the Image
 *      iDesiredCY [I] The desired height of the Image
 *      nFlags     [I] The flags from CopyImage
 *
 * RETURNS
 *     Success: The new handle of the Image
 *
 * NOTES
 *     LR_COPYDELETEORG and LR_MONOCHROME are currently not implemented.
1070
 *     LR_MONOCHROME should be implemented by CreateIconFromResourceEx.
1071 1072
 *     LR_COPYFROMRESOURCE will only work if the Image is in the Cache.
 *
1073
 *
1074 1075
 */

1076
static HICON CURSORICON_ExtCopy(HICON hIcon, UINT nType,
1077 1078
                                INT iDesiredCX, INT iDesiredCY,
                                UINT nFlags)
1079
{
1080
    HICON hNew=0;
1081

1082 1083
    TRACE_(icon)("hIcon %p, nType %u, iDesiredCX %i, iDesiredCY %i, nFlags %u\n",
                 hIcon, nType, iDesiredCX, iDesiredCY, nFlags);
1084

1085
    if(hIcon == 0)
1086
    {
1087
        return 0;
1088 1089 1090 1091 1092
    }

    /* Best Fit or Monochrome */
    if( (nFlags & LR_COPYFROMRESOURCE
        && (iDesiredCX > 0 || iDesiredCY > 0))
1093
        || nFlags & LR_MONOCHROME)
1094
    {
1095
        ICONCACHE* pIconCache = CURSORICON_FindCache(hIcon);
1096

1097
        /* Not Found in Cache, then do a straight copy
1098 1099 1100
        */
        if(pIconCache == NULL)
        {
1101
            hNew = CURSORICON_Copy(0, hIcon);
1102 1103 1104 1105 1106 1107 1108
            if(nFlags & LR_COPYFROMRESOURCE)
            {
                TRACE_(icon)("LR_COPYFROMRESOURCE: Failed to load from cache\n");
            }
        }
        else
        {
1109
            int iTargetCY = iDesiredCY, iTargetCX = iDesiredCX;
1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123
            LPBYTE pBits;
            HANDLE hMem;
            HRSRC hRsrc;
            DWORD dwBytesInRes;
            WORD wResId;
            CURSORICONDIR *pDir;
            CURSORICONDIRENTRY *pDirEntry;
            BOOL bIsIcon = (nType == IMAGE_ICON);

            /* Completing iDesiredCX CY for Monochrome Bitmaps if needed
            */
            if(((nFlags & LR_MONOCHROME) && !(nFlags & LR_COPYFROMRESOURCE))
                || (iDesiredCX == 0 && iDesiredCY == 0))
            {
1124
                iDesiredCY = GetSystemMetrics(bIsIcon ?
1125
                    SM_CYICON : SM_CYCURSOR);
1126
                iDesiredCX = GetSystemMetrics(bIsIcon ?
1127 1128 1129
                    SM_CXICON : SM_CXCURSOR);
            }

1130
            /* Retrieve the CURSORICONDIRENTRY
1131
            */
1132 1133
            if (!(hMem = LoadResource( pIconCache->hModule ,
                            pIconCache->hGroupRsrc)))
1134 1135 1136
            {
                return 0;
            }
1137
            if (!(pDir = (CURSORICONDIR*)LockResource( hMem )))
1138 1139 1140 1141
            {
                return 0;
            }

1142
            /* Find Best Fit
1143 1144 1145
            */
            if(bIsIcon)
            {
1146 1147
                pDirEntry = CURSORICON_FindBestIconRes(
                                pDir, iDesiredCX, iDesiredCY, 256 );
1148 1149 1150
            }
            else
            {
1151
                pDirEntry = CURSORICON_FindBestCursorRes(
1152 1153 1154 1155 1156 1157 1158
                                pDir, iDesiredCX, iDesiredCY, 1);
            }

            wResId = pDirEntry->wResId;
            dwBytesInRes = pDirEntry->dwBytesInRes;
            FreeResource(hMem);

1159
            TRACE_(icon)("ResID %u, BytesInRes %u, Width %d, Height %d DX %d, DY %d\n",
1160
                wResId, dwBytesInRes,  pDirEntry->ResInfo.icon.bWidth,
1161 1162 1163 1164 1165
                pDirEntry->ResInfo.icon.bHeight, iDesiredCX, iDesiredCY);

            /* Get the Best Fit
            */
            if (!(hRsrc = FindResourceW(pIconCache->hModule ,
1166
                MAKEINTRESOURCEW(wResId), (LPWSTR)(bIsIcon ? RT_ICON : RT_CURSOR))))
1167 1168 1169
            {
                return 0;
            }
1170
            if (!(hMem = LoadResource( pIconCache->hModule , hRsrc )))
1171 1172 1173 1174 1175
            {
                return 0;
            }

            pBits = (LPBYTE)LockResource( hMem );
1176

1177 1178 1179
            if(nFlags & LR_DEFAULTSIZE)
            {
                iTargetCY = GetSystemMetrics(SM_CYICON);
1180
                iTargetCX = GetSystemMetrics(SM_CXICON);
1181
            }
1182 1183 1184

            /* Create a New Icon with the proper dimension
            */
1185
            hNew = CreateIconFromResourceEx( pBits, dwBytesInRes,
1186 1187 1188 1189
                       bIsIcon, 0x00030000, iTargetCX, iTargetCY, nFlags);
            FreeResource(hMem);
        }
    }
1190
    else hNew = CURSORICON_Copy(0, hIcon);
1191 1192 1193
    return hNew;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1194 1195

/***********************************************************************
1196
 *		CreateCursor (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1197
 */
1198 1199 1200
HCURSOR WINAPI CreateCursor( HINSTANCE hInstance,
                                 INT xHotSpot, INT yHotSpot,
                                 INT nWidth, INT nHeight,
Alexandre Julliard's avatar
Alexandre Julliard committed
1201
                                 LPCVOID lpANDbits, LPCVOID lpXORbits )
Alexandre Julliard's avatar
Alexandre Julliard committed
1202
{
1203
    CURSORICONINFO info;
Alexandre Julliard's avatar
Alexandre Julliard committed
1204

1205
    TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1206
                    nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1207 1208 1209 1210 1211 1212 1213 1214 1215

    info.ptHotSpot.x = xHotSpot;
    info.ptHotSpot.y = yHotSpot;
    info.nWidth = nWidth;
    info.nHeight = nHeight;
    info.nWidthBytes = 0;
    info.bPlanes = 1;
    info.bBitsPerPixel = 1;

1216
    return HICON_32(CreateCursorIconIndirect16(0, &info, lpANDbits, lpXORbits));
Alexandre Julliard's avatar
Alexandre Julliard committed
1217 1218 1219 1220
}


/***********************************************************************
1221
 *		CreateIcon (USER.407)
Alexandre Julliard's avatar
Alexandre Julliard committed
1222
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1223 1224 1225
HICON16 WINAPI CreateIcon16( HINSTANCE16 hInstance, INT16 nWidth,
                             INT16 nHeight, BYTE bPlanes, BYTE bBitsPixel,
                             LPCVOID lpANDbits, LPCVOID lpXORbits )
Alexandre Julliard's avatar
Alexandre Julliard committed
1226
{
1227
    CURSORICONINFO info;
Alexandre Julliard's avatar
Alexandre Julliard committed
1228

1229
    TRACE_(icon)("%dx%dx%d, xor=%p, and=%p\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1230
                  nWidth, nHeight, bPlanes * bBitsPixel, lpXORbits, lpANDbits);
1231

1232 1233
    info.ptHotSpot.x = ICON_HOTSPOT;
    info.ptHotSpot.y = ICON_HOTSPOT;
1234 1235 1236 1237 1238 1239
    info.nWidth = nWidth;
    info.nHeight = nHeight;
    info.nWidthBytes = 0;
    info.bPlanes = bPlanes;
    info.bBitsPerPixel = bBitsPixel;

1240
    return CreateCursorIconIndirect16( hInstance, &info, lpANDbits, lpXORbits );
Alexandre Julliard's avatar
Alexandre Julliard committed
1241 1242 1243 1244
}


/***********************************************************************
1245
 *		CreateIcon (USER32.@)
1246
 *
1247 1248 1249
 *  Creates an icon based on the specified bitmaps. The bitmaps must be
 *  provided in a device dependent format and will be resized to
 *  (SM_CXICON,SM_CYICON) and depth converted to match the screen's color
1250
 *  depth. The provided bitmaps must be top-down bitmaps.
1251
 *  Although Windows does not support 15bpp(*) this API must support it
1252 1253
 *  for Winelib applications.
 *
1254
 *  (*) Windows does not support 15bpp but it supports the 555 RGB 16bpp
1255 1256
 *      format!
 *
1257 1258 1259 1260
 * RETURNS
 *  Success: handle to an icon
 *  Failure: NULL
 *
1261
 * FIXME: Do we need to resize the bitmaps?
Alexandre Julliard's avatar
Alexandre Julliard committed
1262
 */
1263
HICON WINAPI CreateIcon(
1264
    HINSTANCE hInstance,  /* [in] the application's hInstance */
1265 1266 1267 1268 1269 1270
    INT       nWidth,     /* [in] the width of the provided bitmaps */
    INT       nHeight,    /* [in] the height of the provided bitmaps */
    BYTE      bPlanes,    /* [in] the number of planes in the provided bitmaps */
    BYTE      bBitsPixel, /* [in] the number of bits per pixel of the lpXORbits bitmap */
    LPCVOID   lpANDbits,  /* [in] a monochrome bitmap representing the icon's mask */
    LPCVOID   lpXORbits)  /* [in] the icon's 'color' bitmap */
Alexandre Julliard's avatar
Alexandre Julliard committed
1271
{
1272
    ICONINFO iinfo;
1273
    HICON hIcon;
Alexandre Julliard's avatar
Alexandre Julliard committed
1274

1275 1276
    TRACE_(icon)("%dx%d, planes %d, bpp %d, xor %p, and %p\n",
                 nWidth, nHeight, bPlanes, bBitsPixel, lpXORbits, lpANDbits);
1277

1278 1279 1280 1281 1282 1283 1284 1285 1286 1287
    iinfo.fIcon = TRUE;
    iinfo.xHotspot = ICON_HOTSPOT;
    iinfo.yHotspot = ICON_HOTSPOT;
    iinfo.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpANDbits );
    iinfo.hbmColor = CreateBitmap( nWidth, nHeight, bPlanes, bBitsPixel, lpXORbits );

    hIcon = CreateIconIndirect( &iinfo );

    DeleteObject( iinfo.hbmMask );
    DeleteObject( iinfo.hbmColor );
1288 1289

    return hIcon;
Alexandre Julliard's avatar
Alexandre Julliard committed
1290 1291 1292 1293
}


/***********************************************************************
1294
 *		CreateCursorIconIndirect (USER.408)
Alexandre Julliard's avatar
Alexandre Julliard committed
1295
 */
1296
HGLOBAL16 WINAPI CreateCursorIconIndirect16( HINSTANCE16 hInstance,
Alexandre Julliard's avatar
Alexandre Julliard committed
1297 1298 1299
                                           CURSORICONINFO *info,
                                           LPCVOID lpANDbits,
                                           LPCVOID lpXORbits )
Alexandre Julliard's avatar
Alexandre Julliard committed
1300
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1301
    HGLOBAL16 handle;
Alexandre Julliard's avatar
Alexandre Julliard committed
1302 1303 1304 1305
    char *ptr;
    int sizeAnd, sizeXor;

    hInstance = GetExePtr( hInstance );  /* Make it a module handle */
Alexandre Julliard's avatar
Alexandre Julliard committed
1306
    if (!lpXORbits || !lpANDbits || info->bPlanes != 1) return 0;
1307
    info->nWidthBytes = get_bitmap_width_bytes(info->nWidth,info->bBitsPerPixel);
Alexandre Julliard's avatar
Alexandre Julliard committed
1308
    sizeXor = info->nHeight * info->nWidthBytes;
1309
    sizeAnd = info->nHeight * get_bitmap_width_bytes( info->nWidth, 1 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1310
    if (!(handle = GlobalAlloc16( GMEM_MOVEABLE,
Alexandre Julliard's avatar
Alexandre Julliard committed
1311 1312
                                  sizeof(CURSORICONINFO) + sizeXor + sizeAnd)))
        return 0;
1313
    FarSetOwner16( handle, hInstance );
Alexandre Julliard's avatar
Alexandre Julliard committed
1314
    ptr = (char *)GlobalLock16( handle );
Alexandre Julliard's avatar
Alexandre Julliard committed
1315 1316 1317
    memcpy( ptr, info, sizeof(*info) );
    memcpy( ptr + sizeof(CURSORICONINFO), lpANDbits, sizeAnd );
    memcpy( ptr + sizeof(CURSORICONINFO) + sizeAnd, lpXORbits, sizeXor );
Alexandre Julliard's avatar
Alexandre Julliard committed
1318
    GlobalUnlock16( handle );
Alexandre Julliard's avatar
Alexandre Julliard committed
1319 1320 1321 1322 1323
    return handle;
}


/***********************************************************************
1324
 *		CopyIcon (USER.368)
Alexandre Julliard's avatar
Alexandre Julliard committed
1325
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1326
HICON16 WINAPI CopyIcon16( HINSTANCE16 hInstance, HICON16 hIcon )
Alexandre Julliard's avatar
Alexandre Julliard committed
1327
{
1328
    TRACE_(icon)("%04x %04x\n", hInstance, hIcon );
1329
    return HICON_16(CURSORICON_Copy(hInstance, HICON_32(hIcon)));
Alexandre Julliard's avatar
Alexandre Julliard committed
1330 1331 1332 1333
}


/***********************************************************************
1334
 *		CopyIcon (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1335
 */
1336
HICON WINAPI CopyIcon( HICON hIcon )
Alexandre Julliard's avatar
Alexandre Julliard committed
1337
{
1338
    TRACE_(icon)("%p\n", hIcon );
1339
    return CURSORICON_Copy( 0, hIcon );
Alexandre Julliard's avatar
Alexandre Julliard committed
1340
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1341 1342 1343


/***********************************************************************
1344
 *		CopyCursor (USER.369)
Alexandre Julliard's avatar
Alexandre Julliard committed
1345
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1346
HCURSOR16 WINAPI CopyCursor16( HINSTANCE16 hInstance, HCURSOR16 hCursor )
Alexandre Julliard's avatar
Alexandre Julliard committed
1347
{
1348
    TRACE_(cursor)("%04x %04x\n", hInstance, hCursor );
1349
    return HICON_16(CURSORICON_Copy(hInstance, HCURSOR_32(hCursor)));
Alexandre Julliard's avatar
Alexandre Julliard committed
1350 1351
}

1352
/**********************************************************************
1353
 *		DestroyIcon32 (USER.610)
1354 1355
 *
 * This routine is actually exported from Win95 USER under the name
1356 1357
 * DestroyIcon32 ...  The behaviour implemented here should mimic
 * the Win95 one exactly, especially the return values, which
1358 1359
 * depend on the setting of various flags.
 */
1360
WORD WINAPI DestroyIcon32( HGLOBAL16 handle, UINT16 flags )
1361 1362 1363
{
    WORD retv;

1364
    TRACE_(icon)("(%04x, %04x)\n", handle, flags );
1365 1366 1367

    /* Check whether destroying active cursor */

1368
    if ( get_user_thread_info()->cursor == HICON_32(handle) )
1369
    {
1370
        WARN_(cursor)("Destroying active cursor!\n" );
1371
        return FALSE;
1372 1373 1374 1375 1376 1377
    }

    /* Try shared cursor/icon first */

    if ( !(flags & CID_NONSHARED) )
    {
1378
        INT count = CURSORICON_DelSharedIcon(HICON_32(handle));
1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390

        if ( count != -1 )
            return (flags & CID_WIN32)? TRUE : (count == 0);

        /* FIXME: OEM cursors/icons should be recognized */
    }

    /* Now assume non-shared cursor/icon */

    retv = GlobalFree16( handle );
    return (flags & CID_RESOURCE)? retv : TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1391

Alexandre Julliard's avatar
Alexandre Julliard committed
1392
/***********************************************************************
1393
 *		DestroyIcon (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1394
 */
1395
BOOL WINAPI DestroyIcon( HICON hIcon )
Alexandre Julliard's avatar
Alexandre Julliard committed
1396
{
1397
    return DestroyIcon32(HICON_16(hIcon), CID_WIN32);
Alexandre Julliard's avatar
Alexandre Julliard committed
1398 1399
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1400 1401

/***********************************************************************
1402
 *		DestroyCursor (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1403
 */
1404
BOOL WINAPI DestroyCursor( HCURSOR hCursor )
Alexandre Julliard's avatar
Alexandre Julliard committed
1405
{
1406
    return DestroyIcon32(HCURSOR_16(hCursor), CID_WIN32);
Alexandre Julliard's avatar
Alexandre Julliard committed
1407 1408 1409
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1410
/***********************************************************************
1411
 *		DrawIcon (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1412
 */
1413
BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
Alexandre Julliard's avatar
Alexandre Julliard committed
1414 1415
{
    CURSORICONINFO *ptr;
1416 1417
    HDC hMemDC;
    HBITMAP hXorBits, hAndBits;
Alexandre Julliard's avatar
Alexandre Julliard committed
1418 1419
    COLORREF oldFg, oldBg;

1420 1421
    TRACE("%p, (%d,%d), %p\n", hdc, x, y, hIcon);

1422
    if (!(ptr = (CURSORICONINFO *)GlobalLock16(HICON_16(hIcon)))) return FALSE;
1423 1424
    if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
    hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1,
Alexandre Julliard's avatar
Alexandre Julliard committed
1425
                               (char *)(ptr+1) );
1426
    hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
Alexandre Julliard's avatar
Alexandre Julliard committed
1427
                               ptr->bBitsPerPixel, (char *)(ptr + 1)
1428
                        + ptr->nHeight * get_bitmap_width_bytes(ptr->nWidth,1) );
1429 1430
    oldFg = SetTextColor( hdc, RGB(0,0,0) );
    oldBg = SetBkColor( hdc, RGB(255,255,255) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1431 1432 1433

    if (hXorBits && hAndBits)
    {
1434 1435 1436 1437 1438
        HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
        BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
        SelectObject( hMemDC, hXorBits );
        BitBlt(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
        SelectObject( hMemDC, hBitTemp );
Alexandre Julliard's avatar
Alexandre Julliard committed
1439
    }
1440 1441 1442
    DeleteDC( hMemDC );
    if (hXorBits) DeleteObject( hXorBits );
    if (hAndBits) DeleteObject( hAndBits );
1443
    GlobalUnlock16(HICON_16(hIcon));
1444 1445
    SetTextColor( hdc, oldFg );
    SetBkColor( hdc, oldBg );
Alexandre Julliard's avatar
Alexandre Julliard committed
1446 1447 1448 1449
    return TRUE;
}

/***********************************************************************
1450
 *		DumpIcon (USER.459)
Alexandre Julliard's avatar
Alexandre Julliard committed
1451
 */
1452
DWORD WINAPI DumpIcon16( SEGPTR pInfo, WORD *lpLen,
Alexandre Julliard's avatar
Alexandre Julliard committed
1453
                       SEGPTR *lpXorBits, SEGPTR *lpAndBits )
Alexandre Julliard's avatar
Alexandre Julliard committed
1454
{
1455
    CURSORICONINFO *info = MapSL( pInfo );
Alexandre Julliard's avatar
Alexandre Julliard committed
1456 1457 1458 1459
    int sizeAnd, sizeXor;

    if (!info) return 0;
    sizeXor = info->nHeight * info->nWidthBytes;
1460
    sizeAnd = info->nHeight * get_bitmap_width_bytes( info->nWidth, 1 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1461 1462
    if (lpAndBits) *lpAndBits = pInfo + sizeof(CURSORICONINFO);
    if (lpXorBits) *lpXorBits = pInfo + sizeof(CURSORICONINFO) + sizeAnd;
Alexandre Julliard's avatar
Alexandre Julliard committed
1463 1464 1465 1466 1467
    if (lpLen) *lpLen = sizeof(CURSORICONINFO) + sizeAnd + sizeXor;
    return MAKELONG( sizeXor, sizeXor );
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1468
/***********************************************************************
1469
 *		SetCursor (USER32.@)
1470 1471 1472 1473
 *
 * Set the cursor shape.
 *
 * RETURNS
Alexandre Julliard's avatar
Alexandre Julliard committed
1474
 *	A handle to the previous cursor shape.
Alexandre Julliard's avatar
Alexandre Julliard committed
1475
 */
1476 1477
HCURSOR WINAPI SetCursor( HCURSOR hCursor /* [in] Handle of cursor to show */ )
{
1478
    struct user_thread_info *thread_info = get_user_thread_info();
1479
    HCURSOR hOldCursor;
Alexandre Julliard's avatar
Alexandre Julliard committed
1480

1481
    if (hCursor == thread_info->cursor) return hCursor;  /* No change */
1482
    TRACE("%p\n", hCursor);
1483 1484
    hOldCursor = thread_info->cursor;
    thread_info->cursor = hCursor;
Alexandre Julliard's avatar
Alexandre Julliard committed
1485
    /* Change the cursor shape only if it is visible */
1486
    if (thread_info->cursor_count >= 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
1487
    {
1488
        USER_Driver->pSetCursor( (CURSORICONINFO*)GlobalLock16(HCURSOR_16(hCursor)) );
1489
        GlobalUnlock16(HCURSOR_16(hCursor));
Alexandre Julliard's avatar
Alexandre Julliard committed
1490
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1491 1492 1493
    return hOldCursor;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1494
/***********************************************************************
1495
 *		ShowCursor (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1496
 */
1497
INT WINAPI ShowCursor( BOOL bShow )
Alexandre Julliard's avatar
Alexandre Julliard committed
1498
{
1499
    struct user_thread_info *thread_info = get_user_thread_info();
1500

1501
    TRACE("%d, count=%d\n", bShow, thread_info->cursor_count );
Alexandre Julliard's avatar
Alexandre Julliard committed
1502 1503 1504

    if (bShow)
    {
1505
        if (++thread_info->cursor_count == 0) /* Show it */
1506
        {
1507
            USER_Driver->pSetCursor((CURSORICONINFO*)GlobalLock16(HCURSOR_16(thread_info->cursor)));
1508
            GlobalUnlock16(HCURSOR_16(thread_info->cursor));
1509
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1510 1511 1512
    }
    else
    {
1513 1514
        if (--thread_info->cursor_count == -1) /* Hide it */
            USER_Driver->pSetCursor( NULL );
Alexandre Julliard's avatar
Alexandre Julliard committed
1515
    }
1516
    return thread_info->cursor_count;
Alexandre Julliard's avatar
Alexandre Julliard committed
1517 1518
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1519
/***********************************************************************
1520
 *		GetCursor (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1521
 */
1522
HCURSOR WINAPI GetCursor(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
1523
{
1524
    return get_user_thread_info()->cursor;
Alexandre Julliard's avatar
Alexandre Julliard committed
1525 1526 1527 1528
}


/***********************************************************************
1529
 *		ClipCursor (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1530
 */
1531
BOOL WINAPI ClipCursor( const RECT *rect )
Alexandre Julliard's avatar
Alexandre Julliard committed
1532
{
1533 1534 1535 1536 1537 1538 1539
    RECT virt;

    SetRect( &virt, 0, 0, GetSystemMetrics( SM_CXVIRTUALSCREEN ),
                          GetSystemMetrics( SM_CYVIRTUALSCREEN ) );
    OffsetRect( &virt, GetSystemMetrics( SM_XVIRTUALSCREEN ),
                       GetSystemMetrics( SM_YVIRTUALSCREEN ) );

1540 1541 1542
    TRACE( "Clipping to: %s was: %s screen: %s\n", wine_dbgstr_rect(rect),
           wine_dbgstr_rect(&CURSOR_ClipRect), wine_dbgstr_rect(&virt) );

1543 1544 1545
    if (!IntersectRect( &CURSOR_ClipRect, &virt, rect ))
        CURSOR_ClipRect = virt;

1546
    USER_Driver->pClipCursor( rect );
Alexandre Julliard's avatar
Alexandre Julliard committed
1547 1548 1549 1550 1551
    return TRUE;
}


/***********************************************************************
1552
 *		GetClipCursor (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1553
 */
1554
BOOL WINAPI GetClipCursor( RECT *rect )
Alexandre Julliard's avatar
Alexandre Julliard committed
1555
{
1556 1557 1558
    /* If this is first time - initialize the rect */
    if (IsRectEmpty( &CURSOR_ClipRect )) ClipCursor( NULL );

1559
    return CopyRect( rect, &CURSOR_ClipRect );
Alexandre Julliard's avatar
Alexandre Julliard committed
1560 1561
}

1562 1563 1564 1565 1566 1567

/***********************************************************************
 *		SetSystemCursor (USER32.@)
 */
BOOL WINAPI SetSystemCursor(HCURSOR hcur, DWORD id)
{
1568
    FIXME("(%p,%08x),stub!\n",  hcur, id);
1569 1570 1571 1572
    return TRUE;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1573
/**********************************************************************
1574
 *		LookupIconIdFromDirectoryEx (USER.364)
Alexandre Julliard's avatar
Alexandre Julliard committed
1575 1576 1577
 *
 * FIXME: exact parameter sizes
 */
1578
INT16 WINAPI LookupIconIdFromDirectoryEx16( LPBYTE dir, BOOL16 bIcon,
1579
                                            INT16 width, INT16 height, UINT16 cFlag )
1580 1581 1582 1583 1584 1585 1586 1587 1588
{
    return LookupIconIdFromDirectoryEx( dir, bIcon, width, height, cFlag );
}

/**********************************************************************
 *		LookupIconIdFromDirectoryEx (USER32.@)
 */
INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE xdir, BOOL bIcon,
             INT width, INT height, UINT cFlag )
Alexandre Julliard's avatar
Alexandre Julliard committed
1589
{
1590
    CURSORICONDIR       *dir = (CURSORICONDIR*)xdir;
1591
    UINT retVal = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1592 1593
    if( dir && !dir->idReserved && (dir->idType & 3) )
    {
1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606
        CURSORICONDIRENTRY* entry;
        HDC hdc;
        UINT palEnts;
        int colors;
        hdc = GetDC(0);
        palEnts = GetSystemPaletteEntries(hdc, 0, 0, NULL);
        if (palEnts == 0)
            palEnts = 256;
        colors = (cFlag & LR_MONOCHROME) ? 2 : palEnts;

        ReleaseDC(0, hdc);

        if( bIcon )
1607
            entry = CURSORICON_FindBestIconRes( dir, width, height, colors );
1608
        else
1609
            entry = CURSORICON_FindBestCursorRes( dir, width, height, 1);
1610

1611
        if( entry ) retVal = entry->wResId;
Alexandre Julliard's avatar
Alexandre Julliard committed
1612
    }
1613
    else WARN_(cursor)("invalid resource directory\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1614 1615 1616 1617
    return retVal;
}

/**********************************************************************
1618
 *              LookupIconIdFromDirectory (USER.?)
Alexandre Julliard's avatar
Alexandre Julliard committed
1619
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1620
INT16 WINAPI LookupIconIdFromDirectory16( LPBYTE dir, BOOL16 bIcon )
Alexandre Julliard's avatar
Alexandre Julliard committed
1621
{
1622
    return LookupIconIdFromDirectoryEx16( dir, bIcon,
1623 1624
           bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
           bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
Alexandre Julliard's avatar
Alexandre Julliard committed
1625
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1626

Alexandre Julliard's avatar
Alexandre Julliard committed
1627
/**********************************************************************
1628
 *              LookupIconIdFromDirectory (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1629
 */
1630
INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
Alexandre Julliard's avatar
Alexandre Julliard committed
1631
{
1632
    return LookupIconIdFromDirectoryEx( dir, bIcon,
1633 1634
           bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
           bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
Alexandre Julliard's avatar
Alexandre Julliard committed
1635 1636
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1637
/**********************************************************************
1638
 *              GetIconID (USER.455)
Alexandre Julliard's avatar
Alexandre Julliard committed
1639
 */
1640
WORD WINAPI GetIconID16( HGLOBAL16 hResource, DWORD resType )
Alexandre Julliard's avatar
Alexandre Julliard committed
1641
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1642
    LPBYTE lpDir = (LPBYTE)GlobalLock16(hResource);
Alexandre Julliard's avatar
Alexandre Julliard committed
1643

1644
    TRACE_(cursor)("hRes=%04x, entries=%i\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1645
                    hResource, lpDir ? ((CURSORICONDIR*)lpDir)->idCount : 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
1646 1647 1648

    switch(resType)
    {
1649 1650 1651 1652 1653 1654 1655
        case RT_CURSOR:
             return (WORD)LookupIconIdFromDirectoryEx16( lpDir, FALSE,
                          GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR), LR_MONOCHROME );
        case RT_ICON:
             return (WORD)LookupIconIdFromDirectoryEx16( lpDir, TRUE,
                          GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0 );
        default:
1656
             WARN_(cursor)("invalid res type %d\n", resType );
Alexandre Julliard's avatar
Alexandre Julliard committed
1657
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1658 1659 1660
    return 0;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1661
/**********************************************************************
1662
 *              LoadCursorIconHandler (USER.336)
Alexandre Julliard's avatar
Alexandre Julliard committed
1663 1664 1665
 *
 * Supposed to load resources of Windows 2.x applications.
 */
1666
HGLOBAL16 WINAPI LoadCursorIconHandler16( HGLOBAL16 hResource, HMODULE16 hModule, HRSRC16 hRsrc )
Alexandre Julliard's avatar
Alexandre Julliard committed
1667
{
1668
    FIXME_(cursor)("(%04x,%04x,%04x): old 2.x resources are not supported!\n",
1669
          hResource, hModule, hRsrc);
Alexandre Julliard's avatar
Alexandre Julliard committed
1670 1671 1672
    return (HGLOBAL16)0;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1673
/**********************************************************************
1674
 *              LoadIconHandler (USER.456)
Alexandre Julliard's avatar
Alexandre Julliard committed
1675
 */
1676
HICON16 WINAPI LoadIconHandler16( HGLOBAL16 hResource, BOOL16 bNew )
Alexandre Julliard's avatar
Alexandre Julliard committed
1677
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1678 1679
    LPBYTE bits = (LPBYTE)LockResource16( hResource );

1680
    TRACE_(cursor)("hRes=%04x\n",hResource);
Alexandre Julliard's avatar
Alexandre Julliard committed
1681

1682
    return HICON_16(CreateIconFromResourceEx( bits, 0, TRUE,
1683
                      bNew ? 0x00030000 : 0x00020000, 0, 0, LR_DEFAULTCOLOR));
Alexandre Julliard's avatar
Alexandre Julliard committed
1684 1685 1686
}

/***********************************************************************
1687
 *              LoadCursorW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1688
 */
1689
HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
Alexandre Julliard's avatar
Alexandre Julliard committed
1690
{
1691 1692
    TRACE("%p, %s\n", hInstance, debugstr_w(name));

1693
    return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0,
1694
                       LR_SHARED | LR_DEFAULTSIZE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1695 1696 1697
}

/***********************************************************************
1698
 *		LoadCursorA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1699
 */
1700
HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
Alexandre Julliard's avatar
Alexandre Julliard committed
1701
{
1702 1703
    TRACE("%p, %s\n", hInstance, debugstr_a(name));

1704
    return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0,
1705
                       LR_SHARED | LR_DEFAULTSIZE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1706
}
1707

Alexandre Julliard's avatar
Alexandre Julliard committed
1708
/***********************************************************************
1709 1710
 *		LoadCursorFromFileW (USER32.@)
 */
1711
HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
1712
{
1713 1714
    TRACE("%s\n", debugstr_w(name));

1715
    return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0,
1716
                       LR_LOADFROMFILE | LR_DEFAULTSIZE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1717
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1718

Alexandre Julliard's avatar
Alexandre Julliard committed
1719
/***********************************************************************
1720 1721
 *		LoadCursorFromFileA (USER32.@)
 */
1722
HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
1723
{
1724 1725
    TRACE("%s\n", debugstr_a(name));

1726
    return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0,
1727
                       LR_LOADFROMFILE | LR_DEFAULTSIZE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1728
}
1729

Alexandre Julliard's avatar
Alexandre Julliard committed
1730
/***********************************************************************
1731
 *		LoadIconW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1732
 */
1733
HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
Alexandre Julliard's avatar
Alexandre Julliard committed
1734
{
1735 1736
    TRACE("%p, %s\n", hInstance, debugstr_w(name));

1737
    return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0,
1738
                       LR_SHARED | LR_DEFAULTSIZE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1739 1740 1741
}

/***********************************************************************
1742
 *              LoadIconA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1743
 */
1744
HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
Alexandre Julliard's avatar
Alexandre Julliard committed
1745
{
1746 1747
    TRACE("%p, %s\n", hInstance, debugstr_a(name));

1748
    return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0,
1749
                       LR_SHARED | LR_DEFAULTSIZE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1750
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1751

1752
/**********************************************************************
1753
 *              GetIconInfo (USER32.@)
1754
 */
1755 1756
BOOL WINAPI GetIconInfo(HICON hIcon, PICONINFO iconinfo)
{
1757
    CURSORICONINFO *ciconinfo;
1758
    INT height;
Alexandre Julliard's avatar
Alexandre Julliard committed
1759

1760
    ciconinfo = GlobalLock16(HICON_16(hIcon));
Alexandre Julliard's avatar
Alexandre Julliard committed
1761
    if (!ciconinfo)
1762
        return FALSE;
1763

1764 1765 1766
    TRACE("%p => %dx%d, %d bpp\n", hIcon,
          ciconinfo->nWidth, ciconinfo->nHeight, ciconinfo->bBitsPerPixel);

1767
    if ( (ciconinfo->ptHotSpot.x == ICON_HOTSPOT) &&
1768
         (ciconinfo->ptHotSpot.y == ICON_HOTSPOT) )
1769 1770
    {
      iconinfo->fIcon    = TRUE;
1771 1772
      iconinfo->xHotspot = ciconinfo->nWidth / 2;
      iconinfo->yHotspot = ciconinfo->nHeight / 2;
1773 1774 1775 1776 1777 1778 1779
    }
    else
    {
      iconinfo->fIcon    = FALSE;
      iconinfo->xHotspot = ciconinfo->ptHotSpot.x;
      iconinfo->yHotspot = ciconinfo->ptHotSpot.y;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1780

1781 1782
    height = ciconinfo->nHeight;

1783 1784 1785
    if (ciconinfo->bBitsPerPixel > 1)
    {
        iconinfo->hbmColor = CreateBitmap( ciconinfo->nWidth, ciconinfo->nHeight,
Alexandre Julliard's avatar
Alexandre Julliard committed
1786 1787 1788
                                ciconinfo->bPlanes, ciconinfo->bBitsPerPixel,
                                (char *)(ciconinfo + 1)
                                + ciconinfo->nHeight *
1789
                                get_bitmap_width_bytes (ciconinfo->nWidth,1) );
1790 1791 1792 1793
    }
    else
    {
        iconinfo->hbmColor = 0;
1794
        height *= 2;
1795 1796 1797
    }

    iconinfo->hbmMask = CreateBitmap ( ciconinfo->nWidth, height,
Alexandre Julliard's avatar
Alexandre Julliard committed
1798 1799
                                1, 1, (char *)(ciconinfo + 1));

1800
    GlobalUnlock16(HICON_16(hIcon));
Alexandre Julliard's avatar
Alexandre Julliard committed
1801

Alexandre Julliard's avatar
Alexandre Julliard committed
1802 1803 1804 1805
    return TRUE;
}

/**********************************************************************
1806
 *		CreateIconIndirect (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1807
 */
1808
HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
1809
{
1810 1811
    DIBSECTION bmpXor;
    BITMAP bmpAnd;
1812
    HICON16 hObj;
1813
    int xor_objsize = 0, sizeXor = 0, sizeAnd, planes, bpp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1814

1815 1816 1817 1818
    TRACE("color %p, mask %p, hotspot %ux%u, fIcon %d\n",
           iconinfo->hbmColor, iconinfo->hbmMask,
           iconinfo->xHotspot, iconinfo->yHotspot, iconinfo->fIcon);

1819 1820
    if (!iconinfo->hbmMask) return 0;

1821 1822 1823
    planes = GetDeviceCaps( screen_dc, PLANES );
    bpp = GetDeviceCaps( screen_dc, BITSPIXEL );

1824 1825
    if (iconinfo->hbmColor)
    {
1826
        xor_objsize = GetObjectW( iconinfo->hbmColor, sizeof(bmpXor), &bmpXor );
1827
        TRACE("color: width %d, height %d, width bytes %d, planes %u, bpp %u\n",
1828 1829 1830 1831 1832
               bmpXor.dsBm.bmWidth, bmpXor.dsBm.bmHeight, bmpXor.dsBm.bmWidthBytes,
               bmpXor.dsBm.bmPlanes, bmpXor.dsBm.bmBitsPixel);
        /* we can use either depth 1 or screen depth for xor bitmap */
        if (bmpXor.dsBm.bmPlanes == 1 && bmpXor.dsBm.bmBitsPixel == 1) planes = bpp = 1;
        sizeXor = bmpXor.dsBm.bmHeight * planes * get_bitmap_width_bytes( bmpXor.dsBm.bmWidth, bpp );
1833 1834 1835 1836 1837
    }
    GetObjectW( iconinfo->hbmMask, sizeof(bmpAnd), &bmpAnd );
    TRACE("mask: width %d, height %d, width bytes %d, planes %u, bpp %u\n",
           bmpAnd.bmWidth, bmpAnd.bmHeight, bmpAnd.bmWidthBytes,
           bmpAnd.bmPlanes, bmpAnd.bmBitsPixel);
Alexandre Julliard's avatar
Alexandre Julliard committed
1838

1839
    sizeAnd = bmpAnd.bmHeight * get_bitmap_width_bytes(bmpAnd.bmWidth, 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
1840

1841
    hObj = GlobalAlloc16( GMEM_MOVEABLE,
1842
                          sizeof(CURSORICONINFO) + sizeXor + sizeAnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
1843 1844
    if (hObj)
    {
1845 1846 1847 1848 1849 1850 1851
        CURSORICONINFO *info;

        info = (CURSORICONINFO *)GlobalLock16( hObj );

        /* If we are creating an icon, the hotspot is unused */
        if (iconinfo->fIcon)
        {
1852 1853
            info->ptHotSpot.x   = ICON_HOTSPOT;
            info->ptHotSpot.y   = ICON_HOTSPOT;
1854 1855 1856
        }
        else
        {
1857 1858
            info->ptHotSpot.x   = iconinfo->xHotspot;
            info->ptHotSpot.y   = iconinfo->yHotspot;
1859 1860
        }

1861 1862
        if (iconinfo->hbmColor)
        {
1863 1864 1865 1866 1867
            info->nWidth        = bmpXor.dsBm.bmWidth;
            info->nHeight       = bmpXor.dsBm.bmHeight;
            info->nWidthBytes   = bmpXor.dsBm.bmWidthBytes;
            info->bPlanes       = planes;
            info->bBitsPerPixel = bpp;
1868 1869 1870 1871
        }
        else
        {
            info->nWidth        = bmpAnd.bmWidth;
1872
            info->nHeight       = bmpAnd.bmHeight / 2;
1873 1874 1875
            info->nWidthBytes   = get_bitmap_width_bytes(bmpAnd.bmWidth, 1);
            info->bPlanes       = 1;
            info->bBitsPerPixel = 1;
1876
        }
1877 1878 1879

        /* Transfer the bitmap bits to the CURSORICONINFO structure */

1880
        /* Some apps pass a color bitmap as a mask, convert it to b/w */
1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891
        if (bmpAnd.bmBitsPixel == 1)
        {
            GetBitmapBits( iconinfo->hbmMask, sizeAnd, (char*)(info + 1) );
        }
        else
        {
            HDC hdc, hdc_mem;
            HBITMAP hbmp_old, hbmp_mem_old, hbmp_mono;

            hdc = GetDC( 0 );
            hdc_mem = CreateCompatibleDC( hdc );
1892

1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908
            hbmp_mono = CreateBitmap( bmpAnd.bmWidth, bmpAnd.bmHeight, 1, 1, NULL );

            hbmp_old = SelectObject( hdc, iconinfo->hbmMask );
            hbmp_mem_old = SelectObject( hdc_mem, hbmp_mono );

            BitBlt( hdc_mem, 0, 0, bmpAnd.bmWidth, bmpAnd.bmHeight, hdc, 0, 0, SRCCOPY );

            SelectObject( hdc, hbmp_old );
            SelectObject( hdc_mem, hbmp_mem_old );

            DeleteDC( hdc_mem );
            ReleaseDC( 0, hdc );

            GetBitmapBits( hbmp_mono, sizeAnd, (char*)(info + 1) );
            DeleteObject( hbmp_mono );
        }
1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955

        if (iconinfo->hbmColor)
        {
            char *dst_bits = (char*)(info + 1) + sizeAnd;

            if (bmpXor.dsBm.bmPlanes == planes && bmpXor.dsBm.bmBitsPixel == bpp)
                GetBitmapBits( iconinfo->hbmColor, sizeXor, dst_bits );
            else
            {
                BITMAPINFO bminfo;
                int dib_width = get_dib_width_bytes( info->nWidth, info->bBitsPerPixel );
                int bitmap_width = get_bitmap_width_bytes( info->nWidth, info->bBitsPerPixel );

                bminfo.bmiHeader.biSize = sizeof(bminfo);
                bminfo.bmiHeader.biWidth = info->nWidth;
                bminfo.bmiHeader.biHeight = info->nHeight;
                bminfo.bmiHeader.biPlanes = info->bPlanes;
                bminfo.bmiHeader.biBitCount = info->bBitsPerPixel;
                bminfo.bmiHeader.biCompression = BI_RGB;
                bminfo.bmiHeader.biSizeImage = info->nHeight * dib_width;
                bminfo.bmiHeader.biXPelsPerMeter = 0;
                bminfo.bmiHeader.biYPelsPerMeter = 0;
                bminfo.bmiHeader.biClrUsed = 0;
                bminfo.bmiHeader.biClrImportant = 0;

                /* swap lines for dib sections */
                if (xor_objsize == sizeof(DIBSECTION))
                    bminfo.bmiHeader.biHeight = -bminfo.bmiHeader.biHeight;

                if (dib_width != bitmap_width)  /* need to fixup alignment */
                {
                    char *src_bits = HeapAlloc( GetProcessHeap(), 0, bminfo.bmiHeader.biSizeImage );

                    if (src_bits && GetDIBits( screen_dc, iconinfo->hbmColor, 0, info->nHeight,
                                               src_bits, &bminfo, DIB_RGB_COLORS ))
                    {
                        int y;
                        for (y = 0; y < info->nHeight; y++)
                            memcpy( dst_bits + y * bitmap_width, src_bits + y * dib_width, bitmap_width );
                    }
                    HeapFree( GetProcessHeap(), 0, src_bits );
                }
                else
                    GetDIBits( screen_dc, iconinfo->hbmColor, 0, info->nHeight,
                               dst_bits, &bminfo, DIB_RGB_COLORS );
            }
        }
1956
        GlobalUnlock16( hObj );
Alexandre Julliard's avatar
Alexandre Julliard committed
1957
    }
1958
    return HICON_32(hObj);
Alexandre Julliard's avatar
Alexandre Julliard committed
1959
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1960

Alexandre Julliard's avatar
Alexandre Julliard committed
1961
/******************************************************************************
1962
 *		DrawIconEx (USER32.@) Draws an icon or cursor on device context
Alexandre Julliard's avatar
Alexandre Julliard committed
1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981
 *
 * NOTES
 *    Why is this using SM_CXICON instead of SM_CXCURSOR?
 *
 * PARAMS
 *    hdc     [I] Handle to device context
 *    x0      [I] X coordinate of upper left corner
 *    y0      [I] Y coordinate of upper left corner
 *    hIcon   [I] Handle to icon to draw
 *    cxWidth [I] Width of icon
 *    cyWidth [I] Height of icon
 *    istep   [I] Index of frame in animated cursor
 *    hbr     [I] Handle to background brush
 *    flags   [I] Icon-drawing flags
 *
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
 */
1982
BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
1983
                            INT cxWidth, INT cyWidth, UINT istep,
1984
                            HBRUSH hbr, UINT flags )
Alexandre Julliard's avatar
Alexandre Julliard committed
1985
{
1986
    CURSORICONINFO *ptr = (CURSORICONINFO *)GlobalLock16(HICON_16(hIcon));
1987
    HDC hDC_off = 0, hMemDC;
1988
    BOOL result = FALSE, DoOffscreen;
1989
    HBITMAP hB_off = 0, hOld = 0;
1990 1991

    if (!ptr) return FALSE;
1992 1993
    TRACE_(icon)("(hdc=%p,pos=%d.%d,hicon=%p,extend=%d.%d,istep=%d,br=%p,flags=0x%08x)\n",
                 hdc,x0,y0,hIcon,cxWidth,cyWidth,istep,hbr,flags );
Alexandre Julliard's avatar
Alexandre Julliard committed
1994

1995
    hMemDC = CreateCompatibleDC (hdc);
Alexandre Julliard's avatar
Alexandre Julliard committed
1996
    if (istep)
1997
        FIXME_(icon)("Ignoring istep=%d\n", istep);
1998 1999
    if (flags & DI_NOMIRROR)
        FIXME_(icon)("Ignoring flag DI_NOMIRROR\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2000

2001
    if (!flags) {
2002 2003
        FIXME_(icon)("no flags set? setting to DI_NORMAL\n");
        flags = DI_NORMAL;
2004 2005
    }

2006 2007
    /* Calculate the size of the destination image.  */
    if (cxWidth == 0)
2008
    {
2009 2010 2011 2012
        if (flags & DI_DEFAULTSIZE)
            cxWidth = GetSystemMetrics (SM_CXICON);
        else
            cxWidth = ptr->nWidth;
2013
    }
2014
    if (cyWidth == 0)
2015
    {
2016 2017 2018 2019
        if (flags & DI_DEFAULTSIZE)
            cyWidth = GetSystemMetrics (SM_CYICON);
        else
            cyWidth = ptr->nHeight;
2020
    }
2021

2022 2023
    DoOffscreen = (GetObjectType( hbr ) == OBJ_BRUSH);

2024
    if (DoOffscreen) {
2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037
        RECT r;

        r.left = 0;
        r.top = 0;
        r.right = cxWidth;
        r.bottom = cxWidth;

        hDC_off = CreateCompatibleDC(hdc);
        hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth);
        if (hDC_off && hB_off) {
            hOld = SelectObject(hDC_off, hB_off);
            FillRect(hDC_off, &r, hbr);
        }
2038
    }
2039 2040

    if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
Alexandre Julliard's avatar
Alexandre Julliard committed
2041
    {
2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061
        HBITMAP hXorBits, hAndBits;
        COLORREF  oldFg, oldBg;
        INT     nStretchMode;

        nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);

        hXorBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
                                  ptr->bPlanes, ptr->bBitsPerPixel,
                                  (char *)(ptr + 1)
                                  + ptr->nHeight *
                                  get_bitmap_width_bytes(ptr->nWidth,1) );
        hAndBits = CreateBitmap ( ptr->nWidth, ptr->nHeight,
                                  1, 1, (char *)(ptr+1) );
        oldFg = SetTextColor( hdc, RGB(0,0,0) );
        oldBg = SetBkColor( hdc, RGB(255,255,255) );

        if (hXorBits && hAndBits)
        {
            HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
            if (flags & DI_MASK)
2062
            {
2063 2064 2065 2066 2067 2068
                if (DoOffscreen)
                    StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
                                hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
                else
                    StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
                                hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCAND);
2069
            }
2070 2071
            SelectObject( hMemDC, hXorBits );
            if (flags & DI_IMAGE)
2072
            {
2073 2074 2075 2076 2077 2078
                if (DoOffscreen)
                    StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
                                hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
                else
                    StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
                                hMemDC, 0, 0, ptr->nWidth, ptr->nHeight, SRCPAINT);
2079
            }
2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092
            SelectObject( hMemDC, hBitTemp );
            result = TRUE;
        }

        SetTextColor( hdc, oldFg );
        SetBkColor( hdc, oldBg );
        if (hXorBits) DeleteObject( hXorBits );
        if (hAndBits) DeleteObject( hAndBits );
        SetStretchBltMode (hdc, nStretchMode);
        if (DoOffscreen) {
            BitBlt(hdc, x0, y0, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
            SelectObject(hDC_off, hOld);
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
2093
    }
2094 2095 2096
    if (hMemDC) DeleteDC( hMemDC );
    if (hDC_off) DeleteDC(hDC_off);
    if (hB_off) DeleteObject(hB_off);
2097
    GlobalUnlock16(HICON_16(hIcon));
Alexandre Julliard's avatar
Alexandre Julliard committed
2098 2099
    return result;
}
2100

2101 2102 2103 2104 2105 2106 2107 2108
/***********************************************************************
 *           DIB_FixColorsToLoadflags
 *
 * Change color table entries when LR_LOADTRANSPARENT or LR_LOADMAP3DCOLORS
 * are in loadflags
 */
static void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags, BYTE pix)
{
2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162
    int colors;
    COLORREF c_W, c_S, c_F, c_L, c_C;
    int incr,i;
    RGBQUAD *ptr;
    int bitmap_type;
    LONG width;
    LONG height;
    WORD bpp;
    DWORD compr;

    if (((bitmap_type = DIB_GetBitmapInfo((BITMAPINFOHEADER*) bmi, &width, &height, &bpp, &compr)) == -1))
    {
        WARN_(resource)("Invalid bitmap\n");
        return;
    }

    if (bpp > 8) return;

    if (bitmap_type == 0) /* BITMAPCOREHEADER */
    {
        incr = 3;
        colors = 1 << bpp;
    }
    else
    {
        incr = 4;
        colors = bmi->bmiHeader.biClrUsed;
        if (colors > 256) colors = 256;
        if (!colors && (bpp <= 8)) colors = 1 << bpp;
    }

    c_W = GetSysColor(COLOR_WINDOW);
    c_S = GetSysColor(COLOR_3DSHADOW);
    c_F = GetSysColor(COLOR_3DFACE);
    c_L = GetSysColor(COLOR_3DLIGHT);

    if (loadflags & LR_LOADTRANSPARENT) {
        switch (bpp) {
        case 1: pix = pix >> 7; break;
        case 4: pix = pix >> 4; break;
        case 8: break;
        default:
            WARN_(resource)("(%d): Unsupported depth\n", bpp);
            return;
        }
        if (pix >= colors) {
            WARN_(resource)("pixel has color index greater than biClrUsed!\n");
            return;
        }
        if (loadflags & LR_LOADMAP3DCOLORS) c_W = c_F;
        ptr = (RGBQUAD*)((char*)bmi->bmiColors+pix*incr);
        ptr->rgbBlue = GetBValue(c_W);
        ptr->rgbGreen = GetGValue(c_W);
        ptr->rgbRed = GetRValue(c_W);
2163
    }
2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181
    if (loadflags & LR_LOADMAP3DCOLORS)
        for (i=0; i<colors; i++) {
            ptr = (RGBQUAD*)((char*)bmi->bmiColors+i*incr);
            c_C = RGB(ptr->rgbRed, ptr->rgbGreen, ptr->rgbBlue);
            if (c_C == RGB(128, 128, 128)) {
                ptr->rgbRed = GetRValue(c_S);
                ptr->rgbGreen = GetGValue(c_S);
                ptr->rgbBlue = GetBValue(c_S);
            } else if (c_C == RGB(192, 192, 192)) {
                ptr->rgbRed = GetRValue(c_F);
                ptr->rgbGreen = GetGValue(c_F);
                ptr->rgbBlue = GetBValue(c_F);
            } else if (c_C == RGB(223, 223, 223)) {
                ptr->rgbRed = GetRValue(c_L);
                ptr->rgbGreen = GetGValue(c_L);
                ptr->rgbBlue = GetBValue(c_L);
            }
        }
2182 2183 2184
}


2185 2186 2187
/**********************************************************************
 *       BITMAP_Load
 */
2188 2189
static HBITMAP BITMAP_Load( HINSTANCE instance, LPCWSTR name,
                            INT desiredx, INT desiredy, UINT loadflags )
2190
{
2191
    HBITMAP hbitmap = 0, orig_bm;
2192 2193 2194
    HRSRC hRsrc;
    HGLOBAL handle;
    char *ptr = NULL;
2195
    BITMAPINFO *info, *fix_info = NULL, *scaled_info = NULL;
2196
    int size;
2197 2198 2199 2200 2201 2202 2203
    BYTE pix;
    char *bits;
    LONG width, height, new_width, new_height;
    WORD bpp_dummy;
    DWORD compr_dummy;
    INT bm_type;
    HDC screen_mem_dc = NULL;
2204

2205 2206
    if (!(loadflags & LR_LOADFROMFILE))
    {
2207 2208 2209 2210 2211
        if (!instance)
        {
            /* OEM bitmap: try to load the resource from user32.dll */
            instance = user32_module;
        }
2212

2213 2214
        if (!(hRsrc = FindResourceW( instance, name, (LPWSTR)RT_BITMAP ))) return 0;
        if (!(handle = LoadResource( instance, hRsrc ))) return 0;
2215

2216
        if ((info = (BITMAPINFO *)LockResource( handle )) == NULL) return 0;
2217 2218 2219
    }
    else
    {
2220 2221
        BITMAPFILEHEADER * bmfh;

2222
        if (!(ptr = map_fileW( name, NULL ))) return 0;
2223
        info = (BITMAPINFO *)(ptr + sizeof(BITMAPFILEHEADER));
2224 2225 2226 2227 2228 2229 2230 2231 2232
        bmfh = (BITMAPFILEHEADER *)ptr;
        if (!(  bmfh->bfType == 0x4d42 /* 'BM' */ &&
                bmfh->bfReserved1 == 0 &&
                bmfh->bfReserved2 == 0))
        {
            WARN("Invalid/unsupported bitmap format!\n");
            UnmapViewOfFile( ptr );
            return 0;
        }
2233
    }
2234

2235
    size = bitmap_info_size(info, DIB_RGB_COLORS);
2236 2237
    fix_info = HeapAlloc(GetProcessHeap(), 0, size);
    scaled_info = HeapAlloc(GetProcessHeap(), 0, size);
2238

2239 2240
    if (!fix_info || !scaled_info) goto end;
    memcpy(fix_info, info, size);
2241

2242 2243
    pix = *((LPBYTE)info + size);
    DIB_FixColorsToLoadflags(fix_info, loadflags, pix);
2244

2245 2246 2247 2248 2249 2250 2251
    memcpy(scaled_info, fix_info, size);
    bm_type = DIB_GetBitmapInfo( &fix_info->bmiHeader, &width, &height,
                                 &bpp_dummy, &compr_dummy);
    if(desiredx != 0)
        new_width = desiredx;
    else
        new_width = width;
2252

2253 2254 2255 2256
    if(desiredy != 0)
        new_height = height > 0 ? desiredy : -desiredy;
    else
        new_height = height;
2257

2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275
    if(bm_type == 0)
    {
        BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)&scaled_info->bmiHeader;
        core->bcWidth = new_width;
        core->bcHeight = new_height;
    }
    else
    {
        scaled_info->bmiHeader.biWidth = new_width;
        scaled_info->bmiHeader.biHeight = new_height;
    }

    if (new_height < 0) new_height = -new_height;

    if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
    if (!(screen_mem_dc = CreateCompatibleDC( screen_dc ))) goto end;

    bits = (char *)info + size;
2276

2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287
    if (loadflags & LR_CREATEDIBSECTION)
    {
        scaled_info->bmiHeader.biCompression = 0; /* DIBSection can't be compressed */
        hbitmap = CreateDIBSection(screen_dc, scaled_info, DIB_RGB_COLORS, NULL, 0, 0);
    }
    else
    {
        if (is_dib_monochrome(fix_info))
            hbitmap = CreateBitmap(new_width, new_height, 1, 1, NULL);
        else
            hbitmap = CreateCompatibleBitmap(screen_dc, new_width, new_height);        
2288
    }
2289

2290 2291 2292 2293 2294 2295 2296 2297
    orig_bm = SelectObject(screen_mem_dc, hbitmap);
    StretchDIBits(screen_mem_dc, 0, 0, new_width, new_height, 0, 0, width, height, bits, fix_info, DIB_RGB_COLORS, SRCCOPY);
    SelectObject(screen_mem_dc, orig_bm);

end:
    if (screen_mem_dc) DeleteDC(screen_mem_dc);
    HeapFree(GetProcessHeap(), 0, scaled_info);
    HeapFree(GetProcessHeap(), 0, fix_info);
2298
    if (loadflags & LR_LOADFROMFILE) UnmapViewOfFile( ptr );
2299

2300 2301 2302 2303
    return hbitmap;
}

/**********************************************************************
2304
 *		LoadImageA (USER32.@)
2305
 *
2306
 * See LoadImageW.
2307 2308 2309 2310 2311 2312 2313
 */
HANDLE WINAPI LoadImageA( HINSTANCE hinst, LPCSTR name, UINT type,
                              INT desiredx, INT desiredy, UINT loadflags)
{
    HANDLE res;
    LPWSTR u_name;

2314
    if (!HIWORD(name))
2315
        return LoadImageW(hinst, (LPCWSTR)name, type, desiredx, desiredy, loadflags);
2316

2317
    __TRY {
2318 2319 2320
        DWORD len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
        u_name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
        MultiByteToWideChar( CP_ACP, 0, name, -1, u_name, len );
2321
    }
2322
    __EXCEPT_PAGE_FAULT {
2323 2324
        SetLastError( ERROR_INVALID_PARAMETER );
        return 0;
2325 2326
    }
    __ENDTRY
2327
    res = LoadImageW(hinst, u_name, type, desiredx, desiredy, loadflags);
2328
    HeapFree(GetProcessHeap(), 0, u_name);
2329 2330 2331 2332 2333
    return res;
}


/******************************************************************************
2334
 *		LoadImageW (USER32.@) Loads an icon, cursor, or bitmap
2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347
 *
 * PARAMS
 *    hinst     [I] Handle of instance that contains image
 *    name      [I] Name of image
 *    type      [I] Type of image
 *    desiredx  [I] Desired width
 *    desiredy  [I] Desired height
 *    loadflags [I] Load flags
 *
 * RETURNS
 *    Success: Handle to newly loaded image
 *    Failure: NULL
 *
2348
 * FIXME: Implementation lacks some features, see LR_ defines in winuser.h
2349 2350 2351 2352
 */
HANDLE WINAPI LoadImageW( HINSTANCE hinst, LPCWSTR name, UINT type,
                INT desiredx, INT desiredy, UINT loadflags )
{
2353 2354 2355
    TRACE_(resource)("(%p,%s,%d,%d,%d,0x%08x)\n",
                     hinst,debugstr_w(name),type,desiredx,desiredy,loadflags);

2356 2357
    if (loadflags & LR_DEFAULTSIZE) {
        if (type == IMAGE_ICON) {
2358 2359 2360
            if (!desiredx) desiredx = GetSystemMetrics(SM_CXICON);
            if (!desiredy) desiredy = GetSystemMetrics(SM_CYICON);
        } else if (type == IMAGE_CURSOR) {
2361
            if (!desiredx) desiredx = GetSystemMetrics(SM_CXCURSOR);
2362 2363
            if (!desiredy) desiredy = GetSystemMetrics(SM_CYCURSOR);
        }
2364 2365 2366 2367
    }
    if (loadflags & LR_LOADFROMFILE) loadflags &= ~LR_SHARED;
    switch (type) {
    case IMAGE_BITMAP:
2368
        return BITMAP_Load( hinst, name, desiredx, desiredy, loadflags );
2369 2370

    case IMAGE_ICON:
2371
        if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
2372
        if (screen_dc)
2373
        {
2374 2375 2376 2377 2378 2379
            UINT palEnts = GetSystemPaletteEntries(screen_dc, 0, 0, NULL);
            if (palEnts == 0) palEnts = 256;
            return CURSORICON_Load(hinst, name, desiredx, desiredy,
                                   palEnts, FALSE, loadflags);
        }
        break;
2380 2381 2382

    case IMAGE_CURSOR:
        return CURSORICON_Load(hinst, name, desiredx, desiredy,
2383
                               1, TRUE, loadflags);
2384 2385 2386 2387 2388
    }
    return 0;
}

/******************************************************************************
2389
 *		CopyImage (USER32.@) Creates new image and copies attributes to it
2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401
 *
 * PARAMS
 *    hnd      [I] Handle to image to copy
 *    type     [I] Type of image to copy
 *    desiredx [I] Desired width of new image
 *    desiredy [I] Desired height of new image
 *    flags    [I] Copy flags
 *
 * RETURNS
 *    Success: Handle to newly created image
 *    Failure: NULL
 *
2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413
 * BUGS
 *    Only Windows NT 4.0 supports the LR_COPYRETURNORG flag for bitmaps,
 *    all other versions (95/2000/XP have been tested) ignore it.
 *
 * NOTES
 *    If LR_CREATEDIBSECTION is absent, the copy will be monochrome for
 *    a monochrome source bitmap or if LR_MONOCHROME is present, otherwise
 *    the copy will have the same depth as the screen.
 *    The content of the image will only be copied if the bit depth of the
 *    original image is compatible with the bit depth of the screen, or
 *    if the source is a DIB section.
 *    The LR_MONOCHROME flag is ignored if LR_CREATEDIBSECTION is present.
2414
 */
2415
HANDLE WINAPI CopyImage( HANDLE hnd, UINT type, INT desiredx,
2416 2417
                             INT desiredy, UINT flags )
{
2418 2419 2420
    TRACE("hnd=%p, type=%u, desiredx=%d, desiredy=%d, flags=%x\n",
          hnd, type, desiredx, desiredy, flags);

2421 2422
    switch (type)
    {
2423
        case IMAGE_BITMAP:
2424
        {
2425 2426 2427 2428
            HBITMAP res = NULL;
            DIBSECTION ds;
            int objSize;
            BITMAPINFO * bi;
2429

2430 2431 2432 2433 2434
            objSize = GetObjectW( hnd, sizeof(ds), &ds );
            if (!objSize) return 0;
            if ((desiredx < 0) || (desiredy < 0)) return 0;

            if (flags & LR_COPYFROMRESOURCE)
2435
            {
2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596
                FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
            }

            if (desiredx == 0) desiredx = ds.dsBm.bmWidth;
            if (desiredy == 0) desiredy = ds.dsBm.bmHeight;

            /* Allocate memory for a BITMAPINFOHEADER structure and a
               color table. The maximum number of colors in a color table
               is 256 which corresponds to a bitmap with depth 8.
               Bitmaps with higher depths don't have color tables. */
            bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
            if (!bi) return 0;

            bi->bmiHeader.biSize        = sizeof(bi->bmiHeader);
            bi->bmiHeader.biPlanes      = ds.dsBm.bmPlanes;
            bi->bmiHeader.biBitCount    = ds.dsBm.bmBitsPixel;
            bi->bmiHeader.biCompression = BI_RGB;

            if (flags & LR_CREATEDIBSECTION)
            {
                /* Create a DIB section. LR_MONOCHROME is ignored */
                void * bits;
                HDC dc = CreateCompatibleDC(NULL);

                if (objSize == sizeof(DIBSECTION))
                {
                    /* The source bitmap is a DIB.
                       Get its attributes to create an exact copy */
                    memcpy(bi, &ds.dsBmih, sizeof(BITMAPINFOHEADER));
                }

                /* Get the color table or the color masks */
                GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);

                bi->bmiHeader.biWidth  = desiredx;
                bi->bmiHeader.biHeight = desiredy;
                bi->bmiHeader.biSizeImage = 0;

                res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
                DeleteDC(dc);
            }
            else
            {
                /* Create a device-dependent bitmap */

                BOOL monochrome = (flags & LR_MONOCHROME);

                if (objSize == sizeof(DIBSECTION))
                {
                    /* The source bitmap is a DIB section.
                       Get its attributes */
                    HDC dc = CreateCompatibleDC(NULL);
                    bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
                    bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
                    GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
                    DeleteDC(dc);

                    if (!monochrome && ds.dsBm.bmBitsPixel == 1)
                    {
                        /* Look if the colors of the DIB are black and white */

                        monochrome = 
                              (bi->bmiColors[0].rgbRed == 0xff
                            && bi->bmiColors[0].rgbGreen == 0xff
                            && bi->bmiColors[0].rgbBlue == 0xff
                            && bi->bmiColors[0].rgbReserved == 0
                            && bi->bmiColors[1].rgbRed == 0
                            && bi->bmiColors[1].rgbGreen == 0
                            && bi->bmiColors[1].rgbBlue == 0
                            && bi->bmiColors[1].rgbReserved == 0)
                            ||
                              (bi->bmiColors[0].rgbRed == 0
                            && bi->bmiColors[0].rgbGreen == 0
                            && bi->bmiColors[0].rgbBlue == 0
                            && bi->bmiColors[0].rgbReserved == 0
                            && bi->bmiColors[1].rgbRed == 0xff
                            && bi->bmiColors[1].rgbGreen == 0xff
                            && bi->bmiColors[1].rgbBlue == 0xff
                            && bi->bmiColors[1].rgbReserved == 0);
                    }
                }
                else if (!monochrome)
                {
                    monochrome = ds.dsBm.bmBitsPixel == 1;
                }

                if (monochrome)
                {
                    res = CreateBitmap(desiredx, desiredy, 1, 1, NULL);
                }
                else
                {
                    HDC screenDC = GetDC(NULL);
                    res = CreateCompatibleBitmap(screenDC, desiredx, desiredy);
                    ReleaseDC(NULL, screenDC);
                }
            }

            if (res)
            {
                /* Only copy the bitmap if it's a DIB section or if it's
                   compatible to the screen */
                BOOL copyContents;

                if (objSize == sizeof(DIBSECTION))
                {
                    copyContents = TRUE;
                }
                else
                {
                    HDC screenDC = GetDC(NULL);
                    int screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
                    ReleaseDC(NULL, screenDC);

                    copyContents = (ds.dsBm.bmBitsPixel == 1 || ds.dsBm.bmBitsPixel == screen_depth);
                }

                if (copyContents)
                {
                    /* The source bitmap may already be selected in a device context,
                       use GetDIBits/StretchDIBits and not StretchBlt  */

                    HDC dc;
                    void * bits;

                    dc = CreateCompatibleDC(NULL);

                    bi->bmiHeader.biWidth = ds.dsBm.bmWidth;
                    bi->bmiHeader.biHeight = ds.dsBm.bmHeight;
                    bi->bmiHeader.biSizeImage = 0;
                    bi->bmiHeader.biClrUsed = 0;
                    bi->bmiHeader.biClrImportant = 0;

                    /* Fill in biSizeImage */
                    GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
                    bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bi->bmiHeader.biSizeImage);

                    if (bits)
                    {
                        HBITMAP oldBmp;

                        /* Get the image bits of the source bitmap */
                        GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS);

                        /* Copy it to the destination bitmap */
                        oldBmp = SelectObject(dc, res);
                        StretchDIBits(dc, 0, 0, desiredx, desiredy,
                                      0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight,
                                      bits, bi, DIB_RGB_COLORS, SRCCOPY);
                        SelectObject(dc, oldBmp);

                        HeapFree(GetProcessHeap(), 0, bits);
                    }

                    DeleteDC(dc);
                }

                if (flags & LR_COPYDELETEORG)
                {
                    DeleteObject(hnd);
                }
2597
            }
2598
            HeapFree(GetProcessHeap(), 0, bi);
2599
            return res;
2600
        }
2601 2602 2603 2604 2605 2606
        case IMAGE_ICON:
                return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags);
        case IMAGE_CURSOR:
                /* Should call CURSORICON_ExtCopy but more testing
                 * needs to be done before we change this
                 */
2607
                if (flags) FIXME("Flags are ignored\n");
2608
                return CopyCursor(hnd);
2609 2610 2611 2612 2613 2614
    }
    return 0;
}


/******************************************************************************
2615
 *		LoadBitmapW (USER32.@) Loads bitmap from the executable file
2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628
 *
 * RETURNS
 *    Success: Handle to specified bitmap
 *    Failure: NULL
 */
HBITMAP WINAPI LoadBitmapW(
    HINSTANCE instance, /* [in] Handle to application instance */
    LPCWSTR name)         /* [in] Address of bitmap resource name */
{
    return LoadImageW( instance, name, IMAGE_BITMAP, 0, 0, 0 );
}

/**********************************************************************
2629
 *		LoadBitmapA (USER32.@)
2630 2631
 *
 * See LoadBitmapW.
2632 2633 2634 2635 2636
 */
HBITMAP WINAPI LoadBitmapA( HINSTANCE instance, LPCSTR name )
{
    return LoadImageA( instance, name, IMAGE_BITMAP, 0, 0, 0 );
}