Click here to Skip to main content
15,867,308 members
Articles / Desktop Programming / ATL
Article

Icon Extractor Shell Extension

Rate me:
Please Sign up or sign in to vote.
5.00/5 (5 votes)
27 Aug 2001Ms-PL3 min read 133.7K   2.1K   38   17
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, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
Web Developer
Romania Romania
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionRegistration is successful but does not display? Pin
forcj92823-Jun-14 22:19
forcj92823-Jun-14 22:19 
QuestionYes but... What about getting a 24x24 icon version of this icon?? Pin
EricF2-Jul-11 20:14
EricF2-Jul-11 20:14 
Generalsome icons have one problem Pin
nenfa15-Dec-09 22:11
nenfa15-Dec-09 22:11 
GeneralInstall and unInstall is succefull! Pin
An Phung Nguyen17-Jan-07 17:50
An Phung Nguyen17-Jan-07 17:50 
GeneralLegal Issues Pin
Anonymous22-Dec-03 9:21
Anonymous22-Dec-03 9:21 
QuestionHow to remove it? Pin
Sprudling6-Feb-02 13:50
Sprudling6-Feb-02 13:50 
AnswerRe: How to remove it? Pin
Tim Smith6-Feb-02 15:19
Tim Smith6-Feb-02 15:19 
QuestionResource leak? Pin
5-Nov-01 9:01
suss5-Nov-01 9:01 
Questionhow can I find which icon in the icon list I extracted is the one lay beside the exe file in windows explorer? Pin
flyingcat29-Aug-01 17:41
flyingcat29-Aug-01 17:41 
AnswerRe: how can I find which icon in the icon list I extracted is the one lay beside the exe file in windows explorer? Pin
Paolo Messina31-Aug-01 14:35
professionalPaolo Messina31-Aug-01 14:35 
GeneralOne little improvment Pin
Michael Dunn24-May-01 16:56
sitebuilderMichael Dunn24-May-01 16:56 
GeneralRe: One little improvment Pin
George Anescu25-May-01 3:16
George Anescu25-May-01 3:16 
GeneralIcon Copyrights Pin
George Chastain24-May-01 5:11
George Chastain24-May-01 5:11 
GeneralRe: Icon Copyrights Pin
George Anescu25-May-01 3:17
George Anescu25-May-01 3:17 
GeneralRe: Icon Copyrights Pin
Mario M.27-May-01 11:56
Mario M.27-May-01 11:56 
GeneralRe: Icon Copyrights Pin
Mal Ross28-May-01 21:26
Mal Ross28-May-01 21:26 
GeneralRe: Icon Copyrights Pin
Anonymous2-Sep-03 5:31
Anonymous2-Sep-03 5:31 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.