Пример #1
0
/*****************************************************************************
 * SIC_OverlayShortcutImage			[internal]
 *
 * NOTES
 *  Creates a new icon as a copy of the passed-in icon, overlayed with a
 *  shortcut image. 
 */
static HICON SIC_OverlayShortcutImage(HICON SourceIcon, BOOL large)
{	ICONINFO SourceIconInfo, ShortcutIconInfo, TargetIconInfo;
	HICON ShortcutIcon, TargetIcon;
	BITMAP SourceBitmapInfo, ShortcutBitmapInfo;
	HDC SourceDC = NULL,
	  ShortcutDC = NULL,
	  TargetDC = NULL,
	  ScreenDC = NULL;
	HBITMAP OldSourceBitmap = NULL,
	  OldShortcutBitmap = NULL,
	  OldTargetBitmap = NULL;

	static int s_imgListIdx = -1;

	/* Get information about the source icon and shortcut overlay */
	if (! GetIconInfo(SourceIcon, &SourceIconInfo)
	    || 0 == GetObjectW(SourceIconInfo.hbmColor, sizeof(BITMAP), &SourceBitmapInfo))
	{
	  return NULL;
	}

	/* search for the shortcut icon only once */
	if (s_imgListIdx == -1)
	    s_imgListIdx = SIC_LoadOverlayIcon(- IDI_SHELL_SHORTCUT);
                           /* FIXME should use icon index 29 instead of the
                              resource id, but not all icons are present yet
                              so we can't use icon indices */

	if (s_imgListIdx != -1)
	{
	    if (large)
	        ShortcutIcon = ImageList_GetIcon(ShellBigIconList, s_imgListIdx, ILD_TRANSPARENT);
	    else
	        ShortcutIcon = ImageList_GetIcon(ShellSmallIconList, s_imgListIdx, ILD_TRANSPARENT);
	} else
	    ShortcutIcon = NULL;

	if (NULL == ShortcutIcon
	    || ! GetIconInfo(ShortcutIcon, &ShortcutIconInfo)
	    || 0 == GetObjectW(ShortcutIconInfo.hbmColor, sizeof(BITMAP), &ShortcutBitmapInfo))
	{
	  return NULL;
	}

	TargetIconInfo = SourceIconInfo;
	TargetIconInfo.hbmMask = NULL;
	TargetIconInfo.hbmColor = NULL;

	/* Setup the source, shortcut and target masks */
	SourceDC = CreateCompatibleDC(NULL);
	if (NULL == SourceDC) goto fail;
	OldSourceBitmap = SelectObject(SourceDC, SourceIconInfo.hbmMask);
	if (NULL == OldSourceBitmap) goto fail;

	ShortcutDC = CreateCompatibleDC(NULL);
	if (NULL == ShortcutDC) goto fail;
	OldShortcutBitmap = SelectObject(ShortcutDC, ShortcutIconInfo.hbmMask);
	if (NULL == OldShortcutBitmap) goto fail;

	TargetDC = CreateCompatibleDC(NULL);
	if (NULL == TargetDC) goto fail;
	TargetIconInfo.hbmMask = CreateCompatibleBitmap(TargetDC, SourceBitmapInfo.bmWidth,
	                                                SourceBitmapInfo.bmHeight);
	if (NULL == TargetIconInfo.hbmMask) goto fail;
	ScreenDC = GetDC(NULL);
	if (NULL == ScreenDC) goto fail;
	TargetIconInfo.hbmColor = CreateCompatibleBitmap(ScreenDC, SourceBitmapInfo.bmWidth,
	                                                 SourceBitmapInfo.bmHeight);
	ReleaseDC(NULL, ScreenDC);
	if (NULL == TargetIconInfo.hbmColor) goto fail;
	OldTargetBitmap = SelectObject(TargetDC, TargetIconInfo.hbmMask);
	if (NULL == OldTargetBitmap) goto fail;

	/* Create the target mask by ANDing the source and shortcut masks */
	if (! BitBlt(TargetDC, 0, 0, SourceBitmapInfo.bmWidth, SourceBitmapInfo.bmHeight,
	             SourceDC, 0, 0, SRCCOPY) ||
	    ! BitBlt(TargetDC, 0, SourceBitmapInfo.bmHeight - ShortcutBitmapInfo.bmHeight,
	             ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight,
	             ShortcutDC, 0, 0, SRCAND))
	{
	  goto fail;
	}

	/* Setup the source and target xor bitmap */
	if (NULL == SelectObject(SourceDC, SourceIconInfo.hbmColor) ||
	    NULL == SelectObject(TargetDC, TargetIconInfo.hbmColor))
	{
	  goto fail;
	}

	/* Copy the source xor bitmap to the target and clear out part of it by using
	   the shortcut mask */
	if (! BitBlt(TargetDC, 0, 0, SourceBitmapInfo.bmWidth, SourceBitmapInfo.bmHeight,
	             SourceDC, 0, 0, SRCCOPY) ||
	    ! BitBlt(TargetDC, 0, SourceBitmapInfo.bmHeight - ShortcutBitmapInfo.bmHeight,
	             ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight,
	             ShortcutDC, 0, 0, SRCAND))
	{
	  goto fail;
	}

	if (NULL == SelectObject(ShortcutDC, ShortcutIconInfo.hbmColor)) goto fail;

	/* Now put in the shortcut xor mask */
	if (! BitBlt(TargetDC, 0, SourceBitmapInfo.bmHeight - ShortcutBitmapInfo.bmHeight,
	             ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight,
	             ShortcutDC, 0, 0, SRCINVERT))
	{
	  goto fail;
	}

	/* Clean up, we're not goto'ing to 'fail' after this so we can be lazy and not set
	   handles to NULL */
	SelectObject(TargetDC, OldTargetBitmap);
	DeleteObject(TargetDC);
	SelectObject(ShortcutDC, OldShortcutBitmap);
	DeleteObject(ShortcutDC);
	SelectObject(SourceDC, OldSourceBitmap);
	DeleteObject(SourceDC);

	/* Create the icon using the bitmaps prepared earlier */
	TargetIcon = CreateIconIndirect(&TargetIconInfo);

	/* CreateIconIndirect copies the bitmaps, so we can release our bitmaps now */
	DeleteObject(TargetIconInfo.hbmColor);
	DeleteObject(TargetIconInfo.hbmMask);

	return TargetIcon;

fail:
	/* Clean up scratch resources we created */
	if (NULL != OldTargetBitmap) SelectObject(TargetDC, OldTargetBitmap);
	if (NULL != TargetIconInfo.hbmColor) DeleteObject(TargetIconInfo.hbmColor);
	if (NULL != TargetIconInfo.hbmMask) DeleteObject(TargetIconInfo.hbmMask);
	if (NULL != TargetDC) DeleteObject(TargetDC);
	if (NULL != OldShortcutBitmap) SelectObject(ShortcutDC, OldShortcutBitmap);
	if (NULL != ShortcutDC) DeleteObject(ShortcutDC);
	if (NULL != OldSourceBitmap) SelectObject(SourceDC, OldSourceBitmap);
	if (NULL != SourceDC) DeleteObject(SourceDC);

	return NULL;
}
Пример #2
0
/*****************************************************************************
 * SIC_OverlayShortcutImage            [internal]
 *
 * NOTES
 *  Creates a new icon as a copy of the passed-in icon, overlayed with a
 *  shortcut image.
 * FIXME: This should go to the ImageList implementation!
 */
static HICON SIC_OverlayShortcutImage(HICON SourceIcon, BOOL large)
{    
    ICONINFO ShortcutIconInfo, TargetIconInfo;
    HICON ShortcutIcon = NULL, TargetIcon;
    BITMAP TargetBitmapInfo, ShortcutBitmapInfo;
    HDC ShortcutDC = NULL,
      TargetDC = NULL;
    HBITMAP OldShortcutBitmap = NULL,
      OldTargetBitmap = NULL;

    static int s_imgListIdx = -1;
    ZeroMemory(&ShortcutIconInfo, sizeof(ShortcutIconInfo));
    ZeroMemory(&TargetIconInfo, sizeof(TargetIconInfo));

    /* Get information about the source icon and shortcut overlay.
     * We will write over the source bitmaps to get the final ones */
    if (! GetIconInfo(SourceIcon, &TargetIconInfo))
        return NULL;
    
    /* Is it possible with the ImageList implementation? */
    if(!TargetIconInfo.hbmColor)
    {
        /* Maybe we'll support this at some point */
        FIXME("1bpp icon wants its overlay!\n");
        goto fail;
    }
        
    if(!GetObjectW(TargetIconInfo.hbmColor, sizeof(BITMAP), &TargetBitmapInfo))
    {
        goto fail;
    }

    /* search for the shortcut icon only once */
    if (s_imgListIdx == -1)
        s_imgListIdx = SIC_LoadOverlayIcon(- IDI_SHELL_SHORTCUT);
                           /* FIXME should use icon index 29 instead of the
                              resource id, but not all icons are present yet
                              so we can't use icon indices */

    if (s_imgListIdx != -1)
    {
        if (large)
            ShortcutIcon = ImageList_GetIcon(ShellBigIconList, s_imgListIdx, ILD_TRANSPARENT);
        else
            ShortcutIcon = ImageList_GetIcon(ShellSmallIconList, s_imgListIdx, ILD_TRANSPARENT);
    } else
        ShortcutIcon = NULL;

    if (!ShortcutIcon || !GetIconInfo(ShortcutIcon, &ShortcutIconInfo))
    {
        goto fail;
    }
    
    /* Is it possible with the ImageLists ? */
    if(!ShortcutIconInfo.hbmColor)
    {
        /* Maybe we'll support this at some point */
        FIXME("Should draw 1bpp overlay!\n");
        goto fail;
    }
    
    if(!GetObjectW(ShortcutIconInfo.hbmColor, sizeof(BITMAP), &ShortcutBitmapInfo))
    {
        goto fail;
    }

    /* Setup the masks */
    ShortcutDC = CreateCompatibleDC(NULL);
    if (NULL == ShortcutDC) goto fail;
    OldShortcutBitmap = (HBITMAP)SelectObject(ShortcutDC, ShortcutIconInfo.hbmMask);
    if (NULL == OldShortcutBitmap) goto fail;

    TargetDC = CreateCompatibleDC(NULL);
    if (NULL == TargetDC) goto fail;
    OldTargetBitmap = (HBITMAP)SelectObject(TargetDC, TargetIconInfo.hbmMask);
    if (NULL == OldTargetBitmap) goto fail;

    /* Create the complete mask by ANDing the source and shortcut masks.
     * NOTE: in an ImageList, all icons have the same dimensions */
    if (!BitBlt(TargetDC, 0, 0, ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight,
                ShortcutDC, 0, 0, SRCAND))
    {
      goto fail;
    }

    /*
     * We must remove or add the alpha component to the shortcut overlay:
     * If we don't, SRCCOPY will copy it to our resulting icon, resulting in a
     * partially transparent icons where it shouldn't be, and to an invisible icon
     * if the underlying icon don't have any alpha channel information. (16bpp only icon for instance).
     * But if the underlying icon has alpha channel information, then we must mark the overlay information
     * as opaque.
     * NOTE: This code sucks(tm) and should belong to the ImageList implementation.
     * NOTE2: there are better ways to do this.
     */
    if(ShortcutBitmapInfo.bmBitsPixel == 32)
    {
        BOOL add_alpha;
        BYTE buffer[sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD)];
        BITMAPINFO* lpbmi = (BITMAPINFO*)buffer;
        PVOID bits;
        PULONG pixel;
        INT i, j;
        
        /* Find if the source bitmap has an alpha channel */
        if(TargetBitmapInfo.bmBitsPixel != 32) add_alpha = FALSE;
        else
        {
            ZeroMemory(buffer, sizeof(buffer));
            lpbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
            lpbmi->bmiHeader.biWidth = TargetBitmapInfo.bmWidth;
            lpbmi->bmiHeader.biHeight = TargetBitmapInfo.bmHeight;
            lpbmi->bmiHeader.biPlanes = 1;
            lpbmi->bmiHeader.biBitCount = 32;
            
            bits = HeapAlloc(GetProcessHeap(), 0, TargetBitmapInfo.bmHeight * TargetBitmapInfo.bmWidthBytes);
            
            if(!bits) goto fail;
            
            if(!GetDIBits(TargetDC, TargetIconInfo.hbmColor, 0, TargetBitmapInfo.bmHeight, bits, lpbmi, DIB_RGB_COLORS))
            {
                ERR("GetBIBits failed!\n");
                HeapFree(GetProcessHeap(), 0, bits);
                goto fail;
            }
            
            i = j = 0;
            pixel = (PULONG)bits;
            
            for(i=0; i<TargetBitmapInfo.bmHeight; i++)
            {
                for(j=0; j<TargetBitmapInfo.bmWidth; j++)
                {
                    add_alpha = (*pixel++ & 0xFF000000) != 0;
                    if(add_alpha) break;
                }
                if(add_alpha) break;
            }
            HeapFree(GetProcessHeap(), 0, bits);
        }
        
        /* Allocate the bits */
        bits = HeapAlloc(GetProcessHeap(), 0, ShortcutBitmapInfo.bmHeight*ShortcutBitmapInfo.bmWidthBytes);
        if(!bits) goto fail;
        
        ZeroMemory(buffer, sizeof(buffer));
        lpbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        lpbmi->bmiHeader.biWidth = ShortcutBitmapInfo.bmWidth;
        lpbmi->bmiHeader.biHeight = ShortcutBitmapInfo.bmHeight;
        lpbmi->bmiHeader.biPlanes = 1;
        lpbmi->bmiHeader.biBitCount = 32;
        
        if(!GetDIBits(TargetDC, ShortcutIconInfo.hbmColor, 0, ShortcutBitmapInfo.bmHeight, bits, lpbmi, DIB_RGB_COLORS))
        {
            ERR("GetBIBits failed!\n");
            HeapFree(GetProcessHeap(), 0, bits);
            goto fail;
        }
        
        pixel = (PULONG)bits;
        /* Remove alpha channel component or make it totally opaque */
        for(i=0; i<ShortcutBitmapInfo.bmHeight; i++)
        {
            for(j=0; j<ShortcutBitmapInfo.bmWidth; j++)
            {
                if(add_alpha) *pixel++ |= 0xFF000000;
                else *pixel++ &= 0x00FFFFFF;
            }
        }
        
        /* GetDIBits return BI_BITFIELDS with masks set to 0, and SetDIBits fails when masks are 0. The irony... */
        lpbmi->bmiHeader.biCompression = BI_RGB;
        
        /* Set the bits again */
        if(!SetDIBits(TargetDC, ShortcutIconInfo.hbmColor, 0, ShortcutBitmapInfo.bmHeight, bits, lpbmi, DIB_RGB_COLORS))
        {
            ERR("SetBIBits failed!, %lu\n", GetLastError());
            HeapFree(GetProcessHeap(), 0, bits);
            goto fail;
        }
        HeapFree(GetProcessHeap(), 0, bits);
    }

    /* Now do the copy. We overwrite the original icon data */
    if (NULL == SelectObject(ShortcutDC, ShortcutIconInfo.hbmColor) ||
        NULL == SelectObject(TargetDC, TargetIconInfo.hbmColor))
        goto fail;
    if (!MaskBlt(TargetDC, 0, 0, ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight,
                 ShortcutDC, 0, 0, ShortcutIconInfo.hbmMask, 0, 0,
                 MAKEROP4(0xAA0000, SRCCOPY)))
    {
        goto fail;
    }

    /* Clean up, we're not goto'ing to 'fail' after this so we can be lazy and not set
       handles to NULL */
    SelectObject(TargetDC, OldTargetBitmap);
    DeleteDC(TargetDC);
    SelectObject(ShortcutDC, OldShortcutBitmap);
    DeleteDC(ShortcutDC);

    /* Create the icon using the bitmaps prepared earlier */
    TargetIcon = CreateIconIndirect(&TargetIconInfo);

    /* CreateIconIndirect copies the bitmaps, so we can release our bitmaps now */
    DeleteObject(TargetIconInfo.hbmColor);
    DeleteObject(TargetIconInfo.hbmMask);
    /* Delete what GetIconInfo gave us */
    DeleteObject(ShortcutIconInfo.hbmColor);
    DeleteObject(ShortcutIconInfo.hbmMask);
    DestroyIcon(ShortcutIcon);

    return TargetIcon;

fail:
    /* Clean up scratch resources we created */
    if (NULL != OldTargetBitmap) SelectObject(TargetDC, OldTargetBitmap);
    if (NULL != TargetDC) DeleteDC(TargetDC);
    if (NULL != OldShortcutBitmap) SelectObject(ShortcutDC, OldShortcutBitmap);
    if (NULL != ShortcutDC) DeleteDC(ShortcutDC);
    if (NULL != TargetIconInfo.hbmColor) DeleteObject(TargetIconInfo.hbmColor);
    if (NULL != TargetIconInfo.hbmMask) DeleteObject(TargetIconInfo.hbmMask);
    if (NULL != ShortcutIconInfo.hbmColor) DeleteObject(ShortcutIconInfo.hbmColor);
    if (NULL != ShortcutIconInfo.hbmMask) DeleteObject(ShortcutIconInfo.hbmMask);
    if (NULL != ShortcutIcon) DestroyIcon(ShortcutIcon);

    return NULL;
}