15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


Распаковщик иконок

Автор: George Anescu

Описание

Наверное Вы иногда замечали, что в некоторых приложения сидят красивые иконки. И, наверное, Вам тоже хотелось поместить эти иконки в свою программу. Давайте посмотрим - как просто можно это сделать.

Проект представляет собой 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;
}