Как сделать мерж 32bit и 8bit иконки?
От: IgorKrasnopeev  
Дата: 09.04.10 13:44
Оценка:
Доброго времени суток,

Подскажите как решить следующую проблему:

В моём Namespace Extension мне надо показывать у иконок файлов различные оверлеи (напрмер, признак, что документ вычекнут).

Для этого я беру стандартную иконку файла (например ворда) и накладываю на неё свою иконку из ресурсов.

Используется модифицированный код из MS KB (http://support.microsoft.com/kb/318876):


HICON CExtractIconImpl::CreateAlphaIcon(WORD size, HICON hIcon, HICON hIcon2)
{
    HDC hMemDC;
    DWORD dwWidth, dwHeight;
    BITMAPV5HEADER bi;

    HBITMAP hBitmap, hOldBitmap;
    void *lpBits;
    HICON hAlphaIcon = NULL;

    dwWidth  = size;  // width of icon
    dwHeight = size;  // height of icon

    ZeroMemory(&bi,sizeof(BITMAPV5HEADER));
    bi.bV5Size           = sizeof(BITMAPV5HEADER);
     
    bi.bV5Width           = dwWidth;
    bi.bV5Height          = dwHeight;
    bi.bV5Planes = 1;
    bi.bV5BitCount = 32;
    bi.bV5Compression = BI_BITFIELDS;
    // The following mask specification specifies a supported 32 BPP
    // alpha format for Windows XP.
    bi.bV5RedMask   =  0x00FF0000;
    bi.bV5GreenMask =  0x0000FF00;
    bi.bV5BlueMask  =  0x000000FF;
    bi.bV5AlphaMask =  0xFF000000; 

    HDC hdc;
    hdc = GetDC(NULL);




    // Create the DIB section with an alpha channel.
    hBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, 
        (void **)&lpBits, NULL, (DWORD)0);

    hMemDC = CreateCompatibleDC(hdc);
    int res = ReleaseDC(NULL,hdc);


    // Draw icons on the DIB section.
    hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);

    res = SetBkMode(hMemDC,TRANSPARENT);
    DWORD* p = (DWORD*)lpBits;
    for (DWORD i = 0; i < dwHeight; ++i)
      for (DWORD j = 0; j < dwHeight; ++j)
        *p++ = 0x00FFFFFF;

    BOOL fRes = DrawIconEx(hMemDC, 0, 0, hIcon, size, size, 0, NULL, DI_NORMAL);
    fRes = DrawIconEx(hMemDC, 0, 0, hIcon2, size, size, 0, NULL, DI_NORMAL);

    SelectObject(hMemDC, hOldBitmap);
    fRes = DeleteDC(hMemDC);

    // Create an empty mask bitmap.
    HBITMAP hMonoBitmap = CreateBitmap(dwWidth,dwHeight,1,1,NULL);

    ICONINFO ii;
    ii.fIcon = TRUE; 
    ii.xHotspot = 0;
    ii.yHotspot = 0;
    ii.hbmMask = hMonoBitmap;
    ii.hbmColor = hBitmap;

    // Create the alpha icon with the alpha DIB section.
    hAlphaIcon = CreateIconIndirect(&ii);

    DeleteObject(hBitmap);          
    DeleteObject(hMonoBitmap); 

    return hAlphaIcon;
}


HICON'ы перед этим достаются из ресурсов так:

// иконка типа файла
    res = PrivateExtractIcons(pszFile, nIconIndex, wSize, wSize, 
                              &hIcon, &pIconId, 1, LR_CREATEDIBSECTION);

// иконка оверлея из моего модуля
    HICON hOverlay = (HICON)LoadImage(g_hInstance, MAKEINTRESOURCE(wOverlayResource), 
                        IMAGE_ICON, wSize, wSize, LR_CREATEDIBSECTION);


Сначала я сделал у себя в ресурсах только 32bit иконки.
Потом выяснилось, что когда заходишь с удалённого компа моя оверлейная иконка забивает иконку типа,
т.е. вместо того чтобы показываться поверх иконки типа — показывается на белом фоне.

Я выяснил, что это происходило из-за того, что при таком подключении использовались 8bit иконки (для иконки типа), а у меня таких не было.

После добавления к моим ресурсам нужных 8bit форматов (и попутного гемора с маской) все начало работать нормально и с удалённого компа.

Но тут подкрался он самый .

Если в качестве иконки типа используется иконка у которой нет 32bit формата (например первая иконка shell32.dll — там только 8 и 4 битные форматы) опять те же грабли — моя иконка на белом фоне.

Т.е. я так понимаю что когда делаешь DrawIconEx 8bit иконки с маской, а потом 32bit иконки с альфой — происходит какой-то косяк с прозрачностью.
(наоборот, кстати, работает — я вижу свои торчащие иконки из-под иконки типа файла)

Подскажите, может есть другой способ или глюк в коде какой?

Я даже руками согласен эти прозрачности окучивать, так не могу найти как получить из HBITMAP значения альфы — что GetPixel, что GetDIBits возвращают 0x00 для альфы
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.