Распаковщик иконок
Описание
Наверное Вы иногда замечали, что в некоторых приложения сидят красивые иконки. И, наверное, Вам тоже хотелось поместить эти иконки в свою программу. Давайте посмотрим - как просто можно это сделать.
Проект представляет собой shell расширение, которое добавляет два пункта во всплывающее меню при нажатии правой кнопкой на .exe или .dll файл в Windows Explorer. Первый пункт меню для распаковки больших иконок, а второй - для маленьких иконок.
При нажатии на эти менюшки, информация о иконке (большая или маленькая) сопируется в clipboard, используя формат BITMAP. Далее можно скопировать содержимое буфера обмена в графический редактор.
Как получить из файла информацию об иконке
Все необходимые действия включены в функции QueryContextMenu() и InvokeCommand() интерфейса IContextMenu. Для получения обработчиков иконок используем следующую функцию:
UINT ExtractIconEx(LPCTSTR lpszFile, int nIconIndex,
HICON FAR *phiconLarge, HICON FAR *phiconSmall, UINT nIcons)
которая позволяет распакавать иконки из исполняемых файлов, динамических библиотек (DLL), или файлов-иконок. Так же можно использовать функцию ExtractIcon() , но она может распаковывать только большие иконки. Итак для начала нам необходимо определить - присутствуют ли иконки в файле. Для этого в функции QueryContextMenu() вызываем ExtractIconEx() с параметром nIconIndex равным -1 и параметрами phiconLarge и phiconSmall установленными в NULL:
int nIcons = (int)ExtractIconEx(m_szFile, -1, NULL, NULL, 0);
Если возвращённое значение больше чем 0 то тогда вставляем во всплывающее меню пункты для больших и маленьких иконок. Таким образом наша shell примочка оперирует со всеми файлами, но пункты меню будут добавлены только для файлов, содержащих иконки. И наконец в функции InvokeCommand() получаем обработчики на оба типа иконок следующим образом:
HICON hIconLarge, hIconSmall;
ExtractIconEx(m_szFile, 0, &hIconLarge, &hIconSmall, 1);
Информацию об иконке распаковывается в структуру ICONINFO используя функцию GetIconInfo() следующим образом:
ICONINFO oIconInfo;
GetIconInfo(hIconLarge, &oIconInfo);
Структура ICONINFO имеет поле hbmColor типа HBITMAP которое и указывает на BITMAP структуру. Используя этот указатель мы можем скопировать информацию о битмапе в clipboard:
BOOL bOpen = ::OpenClipboard(NULL);
if(TRUE==bOpen)
{
::EmptyClipboard();
::SetClipboardData(CF_BITMAP, oIconInfo.hbmColor);
::CloseClipboard();
}
В заключение, после того как мы прекращаем использовать указатели на иконки, необходимо уничтожить их вызовом функции DestroyIcon():
DestroyIcon(hIconLarge);
DestroyIcon(hIconSmall);
А теперь давайте посмотрим на полный код функций QueryContextMenu() и InvokeCommand():
// IContextMenu
HRESULT CIconExtractObj::QueryContextMenu(HMENU hmenu,
UINT uMenuIndex, UINT uCmdID, UINT uidLastCmd, UINT uFlags)
{
//If the flags include CMF_DEFAULTONLY then we shouldn't do anything
if(uFlags & CMF_DEFAULTONLY)
return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);
int nMenus = 0;
//Количество иконок в файле
int nIcons = (int)ExtractIconEx(m_szFile, -1, NULL, NULL, 0);
if(nIcons > 0)
{
InsertMenu(hmenu, uMenuIndex, MF_STRING | MF_BYPOSITION,
uCmdID++, _T("Extract &Large Icon"));
if(NULL != m_hExtractBmpL)
SetMenuItemBitmaps(hmenu, uMenuIndex, MF_BYPOSITION,
m_hExtractBmpL, NULL);
uMenuIndex++;
InsertMenu(hmenu, uMenuIndex, MF_STRING | MF_BYPOSITION,
uCmdID++, _T("Extract &Small Icon"));
if(NULL != m_hExtractBmpS)
SetMenuItemBitmaps(hmenu, uMenuIndex, MF_BYPOSITION,
m_hExtractBmpS, NULL);
uMenuIndex++;
nMenus = 2;
}
return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, nMenus);
}
HRESULT CIconExtractObj::InvokeCommand(LPCMINVOKECOMMANDINFO pCmdInfo)
{
// Если lpVerb реальный указатель на строку,
// то пропускаем данную функцию и выходим
if(0 != HIWORD( pCmdInfo->lpVerb))
return E_INVALIDARG;
//Распаковываем первую иконку
HICON hIconLarge, hIconSmall;
ExtractIconEx(m_szFile, 0, &hIconLarge, &hIconSmall, 1);
ICONINFO oIconInfo;
switch(LOWORD(pCmdInfo->lpVerb))
{
case 0:
GetIconInfo(hIconLarge, &oIconInfo);
break;
case 1:
GetIconInfo(hIconSmall, &oIconInfo);
break;
default:
return E_INVALIDARG;
}
BOOL bOpen = ::OpenClipboard(NULL);
if(TRUE==bOpen)
{
::EmptyClipboard();
::SetClipboardData(CF_BITMAP, oIconInfo.hbmColor);
::CloseClipboard();
}
//Destroy the icons
DestroyIcon(hIconLarge);
DestroyIcon(hIconSmall);
return S_OK;
}