Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Icon Extractor Shell Extension

0.00/5 (No votes)
27 Aug 2001 1  
A context menu handler shell extension for extracting icons from .exe and .dll files

Introduction

Sometimes you can see some applications with very interesting icons and maybe you would like to use the same or similar icons in your applications. In this article I will show how you can easily do this. This article is not a tutorial about how to develop shell extensions and particularly context menu handlers. For understanding all the needed details I recommend the excellent series of articles by Michael Dunn published here at CodeProject: "The Complete Idiot's Guide to Writing Shell Extensions" and particularly Part I. My fully functional project IconExtract.zip is developed using ATL and COM and is structured similarly to the project described in the above mentioned article so that all the explanations given there are applicable. This shell extension will add two menu items to the context menu when you right click on an .exe or .dll file in Windows Explorer, one menu item is for extracting the large icon and the other one is for extracting the small icon. By clicking on these menu items you copy the corresponding icon information (large or small) in the clipboard in the BITMAP format. Later you can paste this information in a graphical editor, for example in the one used by the Visual C++ environment and you can modify it as you want and use similar icons in your own applications.

I will present just the specific details about how to extract icon information from files and how to copy this information in the clipboard in order to be later saved.

How to extract icon information from files

All the specific actions are implemented in the QueryContextMenu() and InvokeCommand() functions of the IContextMenu interface. For getting the handles to the icons I used the function:

UINT ExtractIconEx(LPCTSTR lpszFile, int nIconIndex, HICON FAR *phiconLarge, HICON FAR *phiconSmall, UINT nIcons)

which can extract icons from executable files, dynamic-link libraries (DLL), or icon files. The function ExtractIcon() could also be used, but it extracts only the large icons. First we need to see if there are any icons in the file. For this purpose, in the function QueryContextMenu() I called ExtractIconEx() with the nIconIndex parameter set to -1 and the phiconLarge and phiconSmall parameters set both to NULL:

int nIcons = (int)ExtractIconEx(m_szFile, -1, NULL, NULL, 0);

If the returned number is greater than 0 then I insert in the contxet menu the menu items for large and small icon extraction. In this way the shell extension is applicable to all the files, but the Menu Items will be inserted only for the files which contain icons. Later in the InvokeCommand() function I get the handles to both icons with the call:

HICON hIconLarge, hIconSmall;
ExtractIconEx(m_szFile, 0, &hIconLarge, &hIconSmall, 1);

The icon information can be extracted in an ICONINFO structure using the function GetIconInfo() as in the call:

ICONINFO oIconInfo;
GetIconInfo(hIconLarge, &oIconInfo);

The ICONINFO structure has the field hbmColor of type HBITMAP which is a handle to a BITMAP structure. Using this handle we can copy the bitmap information in the clipboard:

BOOL bOpen = ::OpenClipboard(NULL);
if(TRUE==bOpen)
{
  ::EmptyClipboard();
  ::SetClipboardData(CF_BITMAP, oIconInfo.hbmColor);
  ::CloseClipboard();
}

Finally after we finish using the icon handles we must destroy the icons by calling the DestroyIcon() function:

DestroyIcon(hIconLarge);
DestroyIcon(hIconSmall);

Here I present the full code for QueryContextMenu() and InvokeCommand() functions:

// 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;
  //The number of icons in the file

  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)
{
  // If lpVerb really points to a string, ignore this function call and bail out

  if(0 != HIWORD( pCmdInfo->lpVerb))
    return E_INVALIDARG;
  //Extract first icon

  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;
}

Thanks to Michael Dunn for the improvement suggestions I implemented in this update to the article. I hope that you will find the presented information useful!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here