STDMETHODIMP CShellExt::Extract(LPCTSTR /*pszFile*/, UINT /*nIconIndex*/, HICON * phiconLarge, HICON * phiconSmall, UINT nIconSize) { WORD sizeSmall = HIWORD(nIconSize); WORD sizeLarge = LOWORD(nIconSize); ICONINFO iconinfo; BOOL res; HRESULT hrSmall = S_OK, hrLarge = S_OK; if (phiconSmall) hrSmall = LoadShellIcon(sizeSmall, sizeSmall, phiconSmall); if (phiconLarge) hrLarge = LoadShellIcon(sizeLarge, sizeLarge, phiconLarge); if (FAILED(hrSmall) || FAILED(hrLarge)) { InvalidateIcon(phiconSmall, phiconLarge); return S_FALSE; } if (!m_isDynamic || !phiconLarge || sizeLarge < 32) //No modifications required return S_OK; HDC dcEditColor, dcEditMask, dcEditTemp; HFONT font; HBRUSH brush; HPEN pen; BITMAPINFO bmi; HBITMAP hbm; LPDWORD pPix; res = GetIconInfo(*phiconLarge, &iconinfo); if (!res) return S_OK; //abort, the icon is still valid res = DestroyIcon(*phiconLarge); if (!res) return S_OK; else *phiconLarge = NULL; dcEditColor = CreateCompatibleDC(GetDC(0)); dcEditMask = CreateCompatibleDC(GetDC(0)); dcEditTemp = CreateCompatibleDC(GetDC(0)); // Create temp bitmap to render rectangle to ZeroMemory(&bmi, sizeof(bmi)); bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = sizeLarge; bmi.bmiHeader.biHeight = sizeLarge; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; hbm = CreateDIBSection(dcEditTemp, &bmi, DIB_RGB_COLORS, (VOID**)&pPix, NULL, 0); memset(pPix, 0x00FFFFFF, sizeof(DWORD)*sizeLarge*sizeLarge); //initialize to white pixels, no alpha SelectObject(dcEditColor, iconinfo.hbmColor); SelectObject(dcEditMask, iconinfo.hbmMask); SelectObject(dcEditTemp, hbm); LONG calSize = (LONG)(sizeLarge*2/5); LOGFONT lf = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0}}; lf.lfHeight = calSize; lf.lfWeight = FW_NORMAL; lf.lfCharSet = DEFAULT_CHARSET; lstrcpyn(lf.lfFaceName, TEXT("Courier New"), LF_FACESIZE); RECT rectText = {0, 0, 0, 0}; RECT rectBox = {0, 0, 0, 0}; COLORREF backGround = RGB(1, 1, 60); COLORREF textColor = RGB(250,250,250); font = CreateFontIndirect(&lf); brush = CreateSolidBrush(backGround); pen = CreatePen(PS_NULL, 0, backGround); SelectObject(dcEditTemp, font); SelectObject(dcEditTemp, brush); SelectObject(dcEditTemp, pen); SetBkMode(dcEditTemp, TRANSPARENT); //dont clear background when drawing text SetBkColor(dcEditTemp, backGround); SetTextColor(dcEditTemp, textColor); //Calculate size of the displayed string SIZE stringSize; GetTextExtentPoint32(dcEditTemp, m_szFilePath, m_nameLength, &stringSize); stringSize.cx = std::min(stringSize.cx, (LONG)sizeLarge-2); stringSize.cy = std::min(stringSize.cy, (LONG)sizeLarge-2); rectText.top = sizeLarge - stringSize.cy - 1; rectText.left = sizeLarge - stringSize.cx - 1; rectText.bottom = sizeLarge - 1; rectText.right = sizeLarge - 1; rectBox.top = sizeLarge - stringSize.cy - 2; rectBox.left = sizeLarge - stringSize.cx - 2; rectBox.bottom = sizeLarge; rectBox.right = sizeLarge; //Draw the background (rounded) rectangle int elipsSize = calSize/3; RoundRect(dcEditTemp, rectBox.left, rectBox.top, rectBox.right, rectBox.bottom, elipsSize, elipsSize); //Draw text in the rectangle DrawText(dcEditTemp, m_szFilePath, m_nameLength, &rectText, DT_BOTTOM|DT_SINGLELINE|DT_LEFT); //set alpha of non white pixels back to 255 //premultiply alpha //Fill in the mask bitmap (anything not 100% alpha is transparent) int red, green, blue, alpha; for(int y = 0; y < sizeLarge; y++) { for(int x = 0; x < sizeLarge; x++) { DWORD * pix = pPix+(y*sizeLarge+x); red = *pix & 0xFF; green = *pix >> 8 & 0xFF; blue = *pix >> 16 & 0xFF; alpha = *pix >> 24 & 0xFF; if ((*pix << 8) == 0xFFFFFF00) alpha = 0x00; else alpha = 0xFF; red = (red*alpha)/0xFF; green = (green*alpha)/0xFF; blue = (blue*alpha)/0xFF; *pix = RGBA(red, green, blue, alpha); } } BLENDFUNCTION ftn = { AC_SRC_OVER, 0, 0xFF, AC_SRC_ALPHA }; int width = rectBox.right - rectBox.left; int height = rectBox.bottom - rectBox.top; AlphaBlend(dcEditColor, rectBox.left, rectBox.top, stringSize.cx, stringSize.cy, dcEditTemp, rectBox.left, rectBox.top, width, height, ftn); //Adjust the mask image: simply draw the rectangle to it backGround = RGB(0, 0, 0); DeleteBrush(brush); DeletePen(pen); brush = CreateSolidBrush(backGround); pen = CreatePen(PS_NULL, 0, backGround); SelectObject(dcEditMask, brush); SelectObject(dcEditMask, pen); RoundRect(dcEditMask, rectBox.left, rectBox.top, rectBox.right, rectBox.bottom, elipsSize, elipsSize); DeleteDC(dcEditColor); DeleteDC(dcEditMask); DeleteDC(dcEditTemp); DeleteBrush(brush); DeletePen(pen); DeleteFont(font); DeleteBitmap(hbm); *phiconLarge = CreateIconIndirect(&iconinfo); DeleteBitmap(iconinfo.hbmColor); DeleteBitmap(iconinfo.hbmMask); if (*phiconLarge == NULL) { InvalidateIcon(phiconSmall, phiconLarge); return S_FALSE; } return S_OK; }
STDMETHODIMP CShellExt::Extract(LPCTSTR pszFile, UINT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIconSize) { WORD sizeSmall = HIWORD(nIconSize); WORD sizeLarge = LOWORD(nIconSize); ICONINFO iconinfo; BOOL res; HRESULT hrSmall = S_OK, hrLarge = S_OK; if (phiconSmall) hrSmall = LoadShellIcon(sizeSmall, sizeSmall, phiconSmall); if (phiconLarge) hrLarge = LoadShellIcon(sizeLarge, sizeLarge, phiconLarge); if (FAILED(hrSmall) || FAILED(hrLarge)) { InvalidateIcon(phiconSmall, phiconLarge); return S_FALSE; } if (!m_isDynamic || !phiconLarge) //No modifications required return S_OK; HDC dcEditColor, dcEditMask; HGDIOBJ oldBitmapColor, oldBitmapMask, oldFontColor; HFONT font; HBRUSH brush; res = GetIconInfo(*phiconLarge, &iconinfo); if (!res) return S_OK; //abort, the icon is still valid res = DestroyIcon(*phiconLarge); if (!res) return S_OK; else *phiconLarge = NULL; dcEditColor = CreateCompatibleDC(GetDC(0)); dcEditMask = CreateCompatibleDC(GetDC(0)); oldBitmapColor = SelectObject(dcEditColor, iconinfo.hbmColor); oldBitmapMask = SelectObject(dcEditMask, iconinfo.hbmMask); LONG calSize = (LONG)(sizeLarge*2/5); LOGFONT lf = {0}; lf.lfHeight = std::min(calSize, (LONG)15); //this is in pixels. Make no larger than 15 pixels (but smaller is allowed for small icons) lf.lfWeight = FW_NORMAL; lf.lfCharSet = DEFAULT_CHARSET; lstrcpyn(lf.lfFaceName, TEXT("Bitstream Vera Sans Mono"), LF_FACESIZE); LOGBRUSH lbrush; lbrush.lbStyle = BS_SOLID; lbrush.lbHatch = 0; RECT rect = {0}; COLORREF backGround = RGB(1, 1, 1); COLORREF textColor = RGB(255,255,255); //Grab the topleft pixel as the background color COLORREF maskBack = GetPixel(dcEditColor, 0, 0); if (backGround == maskBack) backGround++; //add one, shouldn't be very visible font = CreateFontIndirect(&lf); lbrush.lbColor = backGround; brush = CreateBrushIndirect(&lbrush); oldFontColor = SelectObject(dcEditColor, font); SetBkMode(dcEditColor, TRANSPARENT); //dont clear background when drawing text (doesnt change much, colors are the same) SetBkColor(dcEditColor, backGround); SetTextColor(dcEditColor, textColor); SIZE stringSize; GetTextExtentPoint32(dcEditColor, m_szFilePath, m_nameLength, &stringSize); stringSize.cx = std::min(stringSize.cx, (LONG)sizeLarge-2); stringSize.cy = std::min(stringSize.cy, (LONG)sizeLarge-2); rect.top = sizeLarge - stringSize.cy - 2; rect.left = sizeLarge - stringSize.cx - 1; rect.bottom = sizeLarge; rect.right = sizeLarge-1; FillRect(dcEditColor, &rect, brush); FillRect(dcEditMask, &rect, brush); rect.top += 1; rect.left -= 1; rect.bottom -= 1; rect.right += 1; FillRect(dcEditColor, &rect, brush); FillRect(dcEditMask, &rect, brush); rect.left += 1; DrawText(dcEditColor, m_szFilePath, m_nameLength, &rect, DT_BOTTOM|DT_SINGLELINE|DT_LEFT); SetBkColor(dcEditColor, maskBack); //BitBlt(dcEditMask, 0, 0, sizeLarge, sizeLarge, dcEditColor, 0, 0, SRCCOPY); SelectObject(dcEditColor, oldFontColor); SelectObject(dcEditColor, oldBitmapColor); SelectObject(dcEditMask, oldBitmapMask); DeleteDC(dcEditColor); DeleteDC(dcEditMask); DeleteBrush(brush); *phiconLarge = CreateIconIndirect(&iconinfo); res = DeleteBitmap(iconinfo.hbmColor); res = DeleteBitmap(iconinfo.hbmMask); if (*phiconLarge == NULL) { InvalidateIcon(phiconSmall, phiconLarge); return S_FALSE; } return S_OK; }