Tuesday, March 25, 2008

extract icon from exe

Code based on http://msdn2.microsoft.com/en-us/library/ms997538.aspx.

class CIconExtractor
{
public:
CIconExtractor()
: m_pImage(NULL)
{
}

HRESULT LoadIconFromApp(LPCWSTR pszFileName, CPngImage ** ppImage);

private:
CPngImage * m_pImage;

private:
static BOOL CALLBACK EnumIconProcInit(
HMODULE hModule,
LPCTSTR lpszType,
LPTSTR lpszName,
LONG_PTR lParam);

BOOL EnumIconProc(
HMODULE hModule,
LPCTSTR lpszType,
LPTSTR lpszName);

HRESULT GetResourceBytes(HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, CAtlArray & arRes);
HRESULT LoadIconFromGroup(HMODULE hModule, CAtlArray & arRes);
};

///////////////////////////////////////////////////////////////////////////////
//
HRESULT CIconExtractor::LoadIconFromApp(LPCWSTR pszFileName, CPngImage ** ppImage)
{
HRESULT hr = S_OK;
HMODULE hExe; // handle to existing .EXE file
BOOL bRet;

// Load the .EXE file that contains an icon.
hExe = LoadLibraryEx(pszFileName, NULL, LOAD_LIBRARY_AS_DATAFILE);
if (hExe == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Cleanup;
}

bRet = EnumResourceNames(hExe, RT_GROUP_ICON, EnumIconProcInit, (LONG_PTR)(void*)this);

if(!m_pImage)
{
if(!bRet)
{

hr = HRESULT_FROM_WIN32(GetLastError());
}
else
{
hr = E_FAIL;
}

goto Cleanup;
}

*ppImage = m_pImage;
m_pImage = NULL;

Cleanup:

// Clean up.
if(hExe)
{
FreeLibrary(hExe);
}

if(m_pImage)
{
delete m_pImage;
m_pImage = NULL;
}

return hr;
}

BOOL CALLBACK CIconExtractor::EnumIconProcInit(
HMODULE hModule,
LPCTSTR lpszType,
LPTSTR lpszName,
LONG_PTR lParam)
{
CIconExtractor * pThis = (CIconExtractor*)lParam;
return pThis->EnumIconProc(hModule, lpszType, lpszName);
}

BOOL CIconExtractor::EnumIconProc(
HMODULE hModule,
LPCTSTR lpszType,
LPTSTR lpszName)
{
HRESULT hr = S_OK;
CAtlArray arResGroup;

IFC(GetResourceBytes(hModule, lpszType, lpszName, arResGroup));

IFC(LoadIconFromGroup(hModule, arResGroup));

Cleanup:

SetLastError(NO_ERROR);

return FALSE;
}

HRESULT CIconExtractor::GetResourceBytes(HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, CAtlArray & arRes)
{
HRESULT hr = S_OK;
HGLOBAL hResLoad; // handle to loaded resource
HRSRC hRes; // handle/ptr. to res. info. in hExe
HANDLE hUpdateRes; // update resource handle
void *pbRes; // pointer to resource data
DWORD cbRes;

// Locate the icon resource in the .EXE file.
hRes = FindResource(hModule, lpszName, lpszType);
if (hRes == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Cleanup;
}

// Load the icon
hResLoad = LoadResource(hModule, hRes);
if (hResLoad == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Cleanup;
}

cbRes = SizeofResource(hModule, hRes);

// Lock the dialog box into global memory.
pbRes = LockResource(hResLoad);
if (pbRes == NULL)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Cleanup;
}

arRes.SetCount(cbRes);
CopyMemory(arRes.GetData(), pbRes, cbRes);

Cleanup:

return hr;
}

// descriptor for the icon group
#pragma pack( push )
#pragma pack( 2 )

typedef struct
{
BYTE bWidth; // Width, in pixels, of the image
BYTE bHeight; // Height, in pixels, of the image
BYTE bColorCount; // Number of colors in image (0 if >=8bpp)
BYTE bReserved; // Reserved
WORD wPlanes; // Color Planes
WORD wBitCount; // Bits per pixel
DWORD dwBytesInRes; // how many bytes in this resource?
WORD nID; // the ID
} GRPICONDIRENTRY, *LPGRPICONDIRENTRY;

typedef struct
{
WORD idReserved; // Reserved (must be 0)
WORD idType; // Resource type (1 for icons)
WORD idCount; // How many images?
GRPICONDIRENTRY idEntries[1]; // The entries for each image
} GRPICONDIR, *LPGRPICONDIR;

typedef struct
{
BYTE bWidth; // Width, in pixels, of the image
BYTE bHeight; // Height, in pixels, of the image
BYTE bColorCount; // Number of colors in image (0 if >=8bpp)
BYTE bReserved; // Reserved
WORD wPlanes; // Color Planes
WORD wBitCount; // Bits per pixel
DWORD dwBytesInRes; // how many bytes in this resource?
DWORD dwBytesOffset; // the ID
} ICONHEADER, *LPICONHEADER;


#pragma pack( pop )

HRESULT CIconExtractor::LoadIconFromGroup(HMODULE hModule, CAtlArray & arRes)
{
HRESULT hr = S_OK;
GRPICONDIR * pDir;
WORD i;
GRPICONDIRENTRY * pCur = NULL;
GRPICONDIRENTRY * pBest = NULL;
CAtlArray arIcon;
HICON hIcon = NULL;

if(arRes.GetCount() < sizeof(GRPICONDIR))
{
hr = E_FAIL;
goto Cleanup;
}

pDir = (GRPICONDIR *)(void*)arRes.GetData();
if(pDir->idCount < 1 || arRes.GetCount() < sizeof(GRPICONDIR) + (pDir->idCount - 1) * sizeof(GRPICONDIRENTRY))
{
hr = E_FAIL;
goto Cleanup;
}

//
// find best icon
//
pCur = pBest = &pDir->idEntries[0];
for(i = 0; i < pDir->idCount; i++)
{
pCur = &pDir->idEntries[i];

if(pCur->wBitCount > pBest->wBitCount)
{
pBest = pCur;
}
else if(pCur->bWidth > pBest->bWidth)
{
pBest = pCur;
}
}

//
// load best icon
//
IFC(GetResourceBytes(hModule, RT_ICON, MAKEINTRESOURCE(pBest->nID), arIcon));

hIcon = CreateIconFromResource(arIcon.GetData(), arIcon.GetCount(), TRUE, 0x00030000);
if(!hIcon)
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Cleanup;
}

{
CMyImage WndImage;

if(pBest->wBitCount == 0x20)
{
CMyIcon::Load(arIcon.GetData(), arIcon.GetCount(), WndImage);
}
else
{
CIconToImageConverter cnv;

IFC(cnv.GetImage(hIcon, WndImage));

goto Cleanup;
}

m_pImage = new CPngImage;
if(m_pImage == NULL)
{
goto Cleanup;
}

m_pImage->Encode(WndImage);
}

Cleanup:

if(hIcon)
{
DestroyIcon(hIcon);
}

return hr;
}

No comments: