/*--------------------------------------------------------------------------* * * Microsoft Windows * Copyright (C) Microsoft Corporation, 1992 - 1999 * * File: picon.cpp * * Contents: Implementation file for CPersistableIcon * * History: 19-Nov-98 jeffro Created * *--------------------------------------------------------------------------*/ #include "picon.h" #include "stgio.h" #include "stddbg.h" #include "macros.h" #include "util.h" #include #include // for ExtractIconEx #include // for HIMAGELIST /* * for comdbg.h (assumes client code is ATL-based) */ #include // for CComModule extern CComModule _Module; #include "comdbg.h" const LPCWSTR g_pszCustomDataStorage = L"Custom Data"; const LPCWSTR CPersistableIcon::s_pszIconFileStream = L"Icon"; const LPCWSTR CPersistableIcon::s_pszIconBitsStream = L"Icon Bits"; static HRESULT ReadIcon (IStream* pstm, CSmartIcon& icon); /*+-------------------------------------------------------------------------* * CPersistableIcon::~CPersistableIcon * * *--------------------------------------------------------------------------*/ CPersistableIcon::~CPersistableIcon() { Cleanup(); } /*+-------------------------------------------------------------------------* * CPersistableIcon::Cleanup * * *--------------------------------------------------------------------------*/ void CPersistableIcon::Cleanup() { m_icon32.Release(); m_icon16.Release(); m_Data.Clear(); } /*+-------------------------------------------------------------------------* * CPersistableIcon::operator= * * *--------------------------------------------------------------------------*/ CPersistableIcon& CPersistableIcon::operator= (const CPersistableIconData& data) { if (&data != &m_Data) { m_Data = data; ExtractIcons (); } return (*this); } /*+-------------------------------------------------------------------------* * CPersistableIcon::GetIcon * * Returns an icon of the requested size. * * NOTE: this method cannot use SC's because it is used in mmcshext.dll, * which doesn't have access to mmcbase.dll, where SC is implemented. *--------------------------------------------------------------------------*/ HRESULT CPersistableIcon::GetIcon (int nIconSize, CSmartIcon& icon) const { HRESULT hr = S_OK; switch (nIconSize) { /* * standard sizes can be returned directly */ case 16: icon = m_icon16; break; case 32: icon = m_icon32; break; /* * non-standard sizes need to be scaled */ default: /* * find the icon whose size is nearest to the requested size; * that one should scale with the most fidelity */ const CSmartIcon& iconSrc = (abs (nIconSize-16) < abs (nIconSize-32)) ? m_icon16 : m_icon32; icon.Attach ((HICON) CopyImage ((HANDLE)(HICON) iconSrc, IMAGE_ICON, nIconSize, nIconSize, 0)); /* * if the CopyImage failed, get the error code */ if (icon == NULL) { hr = HRESULT_FROM_WIN32 (GetLastError()); /* * just in case CopyImage failed without setting the last error */ if (SUCCEEDED (hr)) hr = E_FAIL; } break; } return (hr); } /*+-------------------------------------------------------------------------* * ExtractIcons * * *--------------------------------------------------------------------------*/ bool CPersistableIcon::ExtractIcons () { /* * clean out existing contents of our CSmartIcons */ m_icon32.Release(); m_icon16.Release(); /* * extract the icons from the icon file */ HICON hLargeIcon = NULL; HICON hSmallIcon = NULL; bool fSuccess = ExtractIconEx (m_Data.m_strIconFile.data(), m_Data.m_nIndex, &hLargeIcon, &hSmallIcon, 1); /* * if successful, attach them to our smart icons for resource management; * otherwise, clean up anything that might have been returned */ if (fSuccess) { m_icon32.Attach (hLargeIcon); m_icon16.Attach (hSmallIcon); } else { if (hLargeIcon != NULL) DestroyIcon (hLargeIcon); if (hSmallIcon != NULL) DestroyIcon (hSmallIcon); } return (fSuccess); } /*+-------------------------------------------------------------------------* * CPersistableIcon::Load * * *--------------------------------------------------------------------------*/ HRESULT CPersistableIcon::Load (LPCWSTR pszFilename) { HRESULT hr = E_FAIL; do // not a loop { IStoragePtr spRootStg; IStoragePtr spDefaultIconStg; hr = OpenDebugStorage (pszFilename, STGM_READ | STGM_SHARE_DENY_WRITE, &spRootStg); BREAK_ON_FAIL (hr); hr = OpenDebugStorage (spRootStg, g_pszCustomDataStorage, STGM_READ | STGM_SHARE_EXCLUSIVE, &spDefaultIconStg); BREAK_ON_FAIL (hr); hr = Load (spDefaultIconStg); } while (false); return (hr); } HRESULT CPersistableIcon::Load (IStorage* pStorage) { HRESULT hr; try { /* * read the icon data from the stream */ IStreamPtr spStm; hr = OpenDebugStream (pStorage, s_pszIconFileStream, STGM_READ | STGM_SHARE_EXCLUSIVE, &spStm); THROW_ON_FAIL (hr); *spStm >> m_Data; hr = OpenDebugStream (pStorage, s_pszIconBitsStream, STGM_READ | STGM_SHARE_EXCLUSIVE, &spStm); THROW_ON_FAIL (hr); hr = ReadIcon (spStm, m_icon32); THROW_ON_FAIL (hr); hr = ReadIcon (spStm, m_icon16); THROW_ON_FAIL (hr); } catch (_com_error& err) { /* * Bug 393868: If anything failed, make sure we clean up anything * that was partially completed, to leave us in a coherent * (uninitialized) state. */ Cleanup(); hr = err.Error(); } return (hr); } /*+-------------------------------------------------------------------------* * ReadIcon * * *--------------------------------------------------------------------------*/ static HRESULT ReadIcon (IStream* pstm, CSmartIcon& icon) { HIMAGELIST himl = NULL; HRESULT hr = ReadCompatibleImageList (pstm, himl); if (himl != NULL) { icon.Attach (ImageList_GetIcon (himl, 0, ILD_NORMAL)); if (icon != NULL) hr = S_OK; ImageList_Destroy (himl); } return (hr); } /*+-------------------------------------------------------------------------* * operator>> * * Reads a CPersistableIconData from a stream. *--------------------------------------------------------------------------*/ IStream& operator>> (IStream& stm, CPersistableIconData& icon) { /* * Read the stream version */ DWORD dwVersion; stm >> dwVersion; switch (dwVersion) { case 1: stm >> icon.m_nIndex; stm >> icon.m_strIconFile; break; /* * beta custom icon format, migrate it forward */ case 0: { /* * Read the custom icon index */ WORD wIconIndex; stm >> wIconIndex; icon.m_nIndex = wIconIndex; /* * Read the length, in bytes, of the filename */ WORD cbFilename; stm >> cbFilename; /* * Read the custom icon filename (always in Unicode) */ WCHAR wszFilename[MAX_PATH]; if (cbFilename > sizeof (wszFilename)) _com_issue_error (E_FAIL); DWORD cbRead; HRESULT hr = stm.Read (&wszFilename, cbFilename, &cbRead); THROW_ON_FAIL (hr); USES_CONVERSION; icon.m_strIconFile = W2T (wszFilename); break; } default: _com_issue_error (E_FAIL); break; } return (stm); }