Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1605 lines
40 KiB

//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// exticon.cpp
//
// IExtractIcon com object. Used by the shell to obtain icons.
//
// History:
//
// 3/21/97 edwardp Created.
//
////////////////////////////////////////////////////////////////////////////////
//
// Includes
//
#include "stdinc.h"
#include "resource.h"
#include "cdfidl.h"
#include "xmlutil.h"
#include "exticon.h"
#include "dll.h"
#include "persist.h"
//
// Constructor and destructor.
//
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CExtractIcon::CExtractIcon ***
//
// Constructor.
//
////////////////////////////////////////////////////////////////////////////////
CExtractIcon::CExtractIcon (
PCDFITEMIDLIST pcdfidl,
IXMLElementCollection *pIXMLElementCollection
)
: m_cRef(1)
{
ASSERT(CDFIDL_IsValid(pcdfidl));
ASSERT(ILIsEmpty(_ILNext((LPITEMIDLIST)pcdfidl)));
ASSERT(XML_IsCdfidlMemberOf(pIXMLElementCollection, pcdfidl));
ASSERT(NULL == m_bstrIconURL);
ASSERT(FALSE == m_fGleam);
//
// Set the default icon type.
//
if (CDFIDL_IsFolderId(&pcdfidl->mkid))
{
m_iconType = IDI_CLOSESUBCHANNEL;
}
else
{
m_iconType = IDI_STORY;
}
//
// Get the URL for the custom icon.
//
if (pIXMLElementCollection)
{
IXMLElement* pIXMLElement;
HRESULT hr;
if (CDFIDL_GetIndex(pcdfidl) != -1)
{
hr = XML_GetElementByIndex(pIXMLElementCollection,
CDFIDL_GetIndex(pcdfidl), &pIXMLElement);
}
else
{
IXMLElement *pIXMLElementChild;
hr = XML_GetElementByIndex(pIXMLElementCollection, 0, &pIXMLElementChild);
if (pIXMLElementChild)
{
hr = pIXMLElementChild->get_parent(&pIXMLElement);
if (!pIXMLElement)
{
ASSERT(FALSE);
hr = E_FAIL;
}
pIXMLElementChild->Release();
}
}
if (SUCCEEDED(hr))
{
ASSERT(pIXMLElement);
m_bstrIconURL = XML_GetAttribute(pIXMLElement, XML_ICON);
pIXMLElement->Release();
}
}
//
// Don't allow the DLL to unload.
//
TraceMsg(TF_OBJECTS, "+ IExtractIcon");
DllAddRef();
return;
}
// Used for initializing the Root Element
CExtractIcon::CExtractIcon (
PCDFITEMIDLIST pcdfidl,
IXMLElement *pElem
)
: m_cRef(1)
{
ASSERT(CDFIDL_IsValid(pcdfidl));
ASSERT(ILIsEmpty(_ILNext((LPITEMIDLIST)pcdfidl)));
ASSERT(NULL == m_bstrIconURL);
ASSERT(FALSE == m_fGleam);
//
// Set the default icon type.
//
m_iconType = IDI_CHANNEL;
//
// Get the URL for the custom icon.
//
if (pElem)
{
HRESULT hr;
IXMLElement *pDeskElem;
LONG nIndex;
hr = XML_GetDesktopElementFromChannelElement(pElem, &pDeskElem, &nIndex);
if (SUCCEEDED(hr))
{
m_iconType = IDI_DESKTOP;
pDeskElem->Release();
}
m_bstrIconURL = XML_GetAttribute(pElem, XML_ICON);
}
//
// Don't allow the DLL to unload.
//
TraceMsg(TF_OBJECTS, "+ IExtractIcon");
DllAddRef();
return;
}
// this constructor is used for the default channel case where
// we draw the icon information from the desktop.ini case
// to avoid having to parse the XML stuff
CExtractIcon::CExtractIcon( BSTR pstrPath ) : m_cRef(1)
{
ASSERT(NULL == m_bstrIconURL);
ASSERT(FALSE == m_fGleam);
m_iconType = IDI_CHANNEL;
m_bstrIconURL = SysAllocString( pstrPath );
DllAddRef();
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CExtractIcon::~CExtractIcon ***
//
// Destructor.
//
////////////////////////////////////////////////////////////////////////////////
CExtractIcon::~CExtractIcon (
void
)
{
ASSERT(0 == m_cRef);
if (m_bstrIconURL)
SysFreeString(m_bstrIconURL);
//
// Matching Release for the constructor Addref.
//
TraceMsg(TF_OBJECTS, "- IExtractIcon");
DllRelease();
return;
}
//
// IUnknown methods.
//
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CExtractIcon::QueryInterface ***
//
// CExtractIcon QI.
//
////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CExtractIcon::QueryInterface (
REFIID riid,
void **ppv
)
{
ASSERT(ppv);
HRESULT hr;
if (IID_IUnknown == riid || IID_IExtractIcon == riid)
{
AddRef();
*ppv = (IExtractIcon*)this;
hr = S_OK;
}
#ifdef UNICODE
else if (IID_IExtractIconA == riid)
{
AddRef();
*ppv = (IExtractIconA*)this;
hr = S_OK;
}
#endif
else
{
*ppv = NULL;
hr = E_NOINTERFACE;
}
ASSERT((SUCCEEDED(hr) && *ppv) || (FAILED(hr) && NULL == *ppv));
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CExtractIcon::AddRef ***
//
// CExtractIcon AddRef.
//
////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG)
CExtractIcon::AddRef (
void
)
{
ASSERT(m_cRef != 0);
ASSERT(m_cRef < (ULONG)-1);
return ++m_cRef;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CExtractIcon::Release ***
//
// CExtractIcon Release.
//
////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG)
CExtractIcon::Release (
void
)
{
ASSERT (m_cRef != 0);
ULONG cRef = --m_cRef;
if (0 == cRef)
delete this;
return cRef;
}
//
// IExtractIcon methods.
//
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CExtractIcon::GetIconLocation ***
//
//
// Description:
// Returns a name index pair for the icon associated with this cdf item.
//
// Parameters:
// [In] uFlags - GIL_FORSHELL, GIL_OPENICON.
// [Out] szIconFile - The address of the buffer that receives the associated
// icon name. It can be a filename, but doesn't have to
// be.
// [In] cchMax - Size of the buffer that receives the icon location.
// [Out] piIndex - A pointer that receives the icon's index.
// [Out] pwFlags - A pointer the receives flags about the icon.
//
// Return:
// S_OK if an was found.
// S_FALSE if the shell should supply a default icon.
//
// Comments:
// The shell can cache an icon associated with a name index pair. This
// improves performance on subsequent calls for an icon with the same name
// index pair.
//
////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CExtractIcon::GetIconLocation(
UINT uFlags,
LPTSTR szIconFile,
UINT cchMax,
int *piIndex,
UINT *pwFlags
)
{
ASSERT(szIconFile);
ASSERT(piIndex);
ASSERT(pwFlags);
HRESULT hr = E_FAIL;
//TraceMsg(TF_CDFICON, "<IN> CExtractIcon::GetLocation (icon) tid:0x%x",
// GetCurrentThreadId());
if (m_bstrIconURL && (uFlags & GIL_ASYNC))
{
hr = E_PENDING;
}
else
{
if (m_bstrIconURL)
{
hr = GetCustomIconLocation(uFlags, szIconFile, cchMax, piIndex,
pwFlags);
if (FAILED(hr))
{
SysFreeString(m_bstrIconURL);
m_bstrIconURL = NULL;
}
}
if (FAILED(hr))
{
hr = GetDefaultIconLocation(uFlags, szIconFile, cchMax, piIndex,
pwFlags);
}
//
// If szIconFile is a path the shell will only use the filename part
// of the path as the cache index. To ensure a unique index the full
// path must be used. This is accomplished by modifying the path string
// so it is no longer recognized as a path.
//
if (SUCCEEDED(hr) && INDEX_IMAGE == *piIndex)
MungePath(szIconFile);
if (FAILED(hr))
{
*szIconFile = TEXT('\0');
*piIndex = 0;
hr = S_FALSE; // The shell will use a default icon.
}
ASSERT((S_OK == hr && *szIconFile) ||
(S_FALSE == hr && 0 == *szIconFile));
}
//TraceMsg(TF_CDFICON, "<OUT> CExtractIcon::GetLocation (icon) tid:0x%x",
// GetCurrentThreadId());
return hr;
}
#ifdef UNICODE
// IExtractIconA methods.
STDMETHODIMP
CExtractIcon::GetIconLocation(
UINT uFlags,
LPSTR szIconFile,
UINT cchMax,
int *piIndex,
UINT *pwFlags
)
{
HRESULT hr;
WCHAR* pszIconFileW = new WCHAR[cchMax];
if (pszIconFileW == NULL)
return ERROR_OUTOFMEMORY;
hr = GetIconLocation(uFlags, pszIconFileW, cchMax, piIndex, pwFlags);
if (SUCCEEDED(hr))
SHUnicodeToAnsi(pszIconFileW, szIconFile, cchMax);
delete [] pszIconFileW;
return hr;
}
#endif
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CExtractIcon::Extract ***
//
//
// Description:
// Return an icon given the name index pair returned from GetIconLocation.
//
// Parameters:
// [In] pszFile - A pointer to the name associated with the requested
// icon.
// [In] nIconIndex - An index associated with the requested icon.
// [Out] phiconLarge - Pointer to the variable that receives the handle of
// the large icon.
// [Out] phiconSmall - Pointer to the variable that receives the handle of
// the small icon.
// [Out] nIconSize - Value specifying the size, in pixels, of the icon
// required. The LOWORD and HIWORD specify the size of
// the large and small icons, respectively.
//
// Return:
// S_OK if the icon was extracted.
// S_FALSE if the shell should extract the icon assuming the name is a
// filename and the index is the icon index.
//
// Comments:
// The shell may cache the icon returned from this function.
//
// If the icon index indicates that the icon is specified by an internet
// image then custom extraction is required.
//
////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CExtractIcon::Extract(
LPCTSTR pszFile,
UINT nIconIndex,
HICON *phiconLarge,
HICON *phiconSmall,
UINT nIconSize
)
{
HRESULT hr;
TCHAR szPath[MAX_PATH];
TCHAR* pszPath = szPath;
StrCpyN(szPath, pszFile, ARRAYSIZE(szPath) - 1);
//TraceMsg(TF_CDFICON, "<IN> CExtractIcon::Extract (icon) tid:0x%x",
// GetCurrentThreadId());
if (INDEX_IMAGE == nIconIndex)
{
DemungePath(pszPath);
if (m_fGleam && *pszPath == TEXT('G'))
{
pszPath++;
}
IImgCtx* pIImgCtx;
HANDLE hExitThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hExitThreadEvent)
{
#ifdef UNIX
unixEnsureFileScheme(pszPath);
#endif /* UNIX */
hr = SynchronousDownload(pszPath, &pIImgCtx, hExitThreadEvent);
if (SUCCEEDED(hr))
{
ASSERT(pIImgCtx);
*phiconLarge = ExtractImageIcon(LOWORD(nIconSize), pIImgCtx,
m_fGleam);
*phiconSmall = ExtractImageIcon(HIWORD(nIconSize), pIImgCtx,
m_fGleam);
pIImgCtx->Release();
}
SetEvent(hExitThreadEvent);
}
else
{
hr = E_OUTOFMEMORY;
}
}
else if (m_fGleam)
{
// Add gleam to icon for the shell
hr = ExtractGleamedIcon(pszPath + 1, nIconIndex, 0,
phiconLarge, phiconSmall, nIconSize);
}
else
{
hr = S_FALSE; // Let shell extract it.
}
//TraceMsg(TF_CDFICON, "<OUT> CExtractIcon::Extract (icon) tid:0x%x",
// GetCurrentThreadId());
return hr;
}
#ifdef UNICODE
STDMETHODIMP
CExtractIcon::Extract(
LPCSTR pszFile,
UINT nIconIndex,
HICON *phiconLarge,
HICON *phiconSmall,
UINT nIconSize)
{
HRESULT hr;
int cch = lstrlenA(pszFile) + 1;
WCHAR* pszFileW = new WCHAR[cch];
if (pszFileW == NULL)
return ERROR_OUTOFMEMORY;
SHAnsiToUnicode(pszFile, pszFileW, cch);
hr = Extract(pszFileW, nIconIndex, phiconLarge, phiconSmall, nIconSize);
delete [] pszFileW;
return hr;
}
#endif
//
// Helper functions.
//
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CExtractIcon::GetCustomIconLocation ***
//
//
// Description:
// Gets the location string name for an icon specified via a LOGO element
// in a cdf.
//
// Parameters:
// [In] uFlags - GIL_FORSHELL, GIL_OPENICON.
// [Out] szIconFile - The address of the buffer that receives the associated
// icon name.
// [In] cchMax - Size of the buffer that receives the icon location.
// [Out] piIndex - A pointer that receives the icon's index.
// [Out] pwFlags - A pointer the receives flags about the icon.
//
// Return:
// S_OK if the custom icon location was determined.
// E_FAIL if the location couldn't be determined.
//
// Comments:
// If the extension of the image url isn't .ico then it's treated as an
// internet image file. IImgCtx is used to convert these files into icons.
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
CExtractIcon::GetCustomIconLocation(
UINT uFlags,
LPTSTR szIconFile,
UINT cchMax,
int *piIndex,
UINT *pwFlags
)
{
ASSERT(szIconFile);
ASSERT(piIndex);
ASSERT(pwFlags);
HRESULT hr;
ASSERT(m_bstrIconURL);
*piIndex = 0;
*pwFlags = 0;
TCHAR szURL[INTERNET_MAX_URL_LENGTH];
if (SHUnicodeToTChar(m_bstrIconURL, szURL, ARRAYSIZE(szURL)))
{
hr = URLGetLocalFileName(szURL, szIconFile, cchMax, NULL);
#ifdef DEBUG
if (SUCCEEDED(hr))
{
TraceMsg(TF_CDFICON, "[URLGetLocalFileName %s]", szIconFile);
}
else
{
TraceMsg(TF_CDFICON, "[URLGetLocalFileName %s FAILED]",
szURL);
}
#endif // DEBUG
//hr = URLDownloadToCacheFile(NULL, szURL, szIconFile, cchMax, 0, NULL);
if (SUCCEEDED(hr))
{
LPTSTR pszExt = PathFindExtension(szIconFile);
if (*pszExt != TEXT('.') || 0 != StrCmpI(pszExt, TSTR_ICO_EXT))
*piIndex = INDEX_IMAGE;
}
}
else
{
*szIconFile = TEXT('\0');
hr = E_FAIL;
}
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CExtractIcon::GetDefaultIconLocation ***
//
//
// Description:
// Return the location of the defualt icon.
//
// Parameters:
// [In] uFlags - GIL_FORSHELL, GIL_OPENICON.
// [Out] szIconFile - The address of the buffer that receives the associated
// icon name.
// [In] cchMax - Size of the buffer that receives the icon location.
// [Out] piIndex - A pointer that receives the icon's index.
// [Out] pwFlags - A pointer the receives flags about the icon.
//
// Return:
// S_OK if the default location is returned.
// E_FAIL otherwise.
//
// Comments:
// The default icons are in the resource file.
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
CExtractIcon::GetDefaultIconLocation(
UINT uFlags,
LPTSTR szIconFile,
UINT cchMax,
int *piIndex,
UINT *pwFlags
)
{
ASSERT(szIconFile);
ASSERT(piIndex);
ASSERT(pwFlags);
HRESULT hr;
*pwFlags = 0;
ASSERT(g_szModuleName[0]);
StrCpyN(szIconFile, g_szModuleName, cchMax);
if (*szIconFile)
{
switch (m_iconType)
{
case IDI_STORY:
case IDI_CHANNEL:
case IDI_DESKTOP:
*piIndex = - m_iconType;
break;
default:
*piIndex = (uFlags & GIL_OPENICON) ?
(-IDI_OPENSUBCHANNEL) :
(-IDI_CLOSESUBCHANNEL);
break;
}
hr = S_OK;
}
else
{
hr = E_FAIL;
}
ASSERT((SUCCEEDED(hr) && *szIconFile) || FAILED(hr));
return hr;
}
struct ThreadData
{
HANDLE hEvent;
HANDLE hExitThreadEvent;
IImgCtx * pImgCtx;
LPCWSTR pszBuffer;
HRESULT * pHr;
};
DWORD CALLBACK SyncDownloadThread( LPVOID pData )
{
ThreadData * pTD = (ThreadData * ) pData;
HANDLE hExitThreadEvent = pTD->hExitThreadEvent;
CoInitialize(NULL);
pTD->pImgCtx = NULL;
HRESULT hr;
hr = CoCreateInstance(CLSID_IImgCtx, NULL, CLSCTX_INPROC_SERVER,
IID_IImgCtx, (void**)&(pTD->pImgCtx));
if (SUCCEEDED(hr))
{
hr = pTD->pImgCtx->Load(pTD->pszBuffer, 0);
if (SUCCEEDED(hr))
{
ULONG fState;
SIZE sz;
pTD->pImgCtx->GetStateInfo(&fState, &sz, TRUE);
if (!(fState & (IMGLOAD_COMPLETE | IMGLOAD_ERROR)))
{
BOOL fDone = FALSE;
hr = pTD->pImgCtx->SetCallback(ImgCtx_Callback, &fDone);
if (SUCCEEDED(hr))
{
hr = pTD->pImgCtx->SelectChanges(IMGCHG_COMPLETE, 0, TRUE);
if (SUCCEEDED(hr))
{
MSG msg;
BOOL fMsg;
// HACK: restrict the message pump to those messages we know that URLMON and
// HACK: the imageCtx stuff needs, otherwise we will be pumping messages for
// HACK: windows we shouldn't be pumping right now...
while(!fDone )
{
fMsg = PeekMessage(&msg, NULL, WM_USER + 1, WM_USER + 4, PM_REMOVE );
if (!fMsg)
{
fMsg = PeekMessage( &msg, NULL, WM_APP + 2, WM_APP + 2, PM_REMOVE );
}
if (!fMsg)
{
// go to sleep until we get a new message....
WaitMessage();
continue;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
}
hr = pTD->pImgCtx->GetStateInfo(&fState, &sz, TRUE);
if (SUCCEEDED(hr))
hr = (fState & IMGLOAD_ERROR) ? E_FAIL : S_OK;
}
// Must disconnect on the same thread that SetCallback is
// done. This object becomes a primary object on the thread
// which connects the callback function. The primary object
// count is decremented when Disconnect is called, or when the
// object is released. In this case, the release is definitely
// going to happen on a different thread than this one, so we
// need to disconnect the callback function right now before
// returning. There is no further needs for callbacks at this
// point.
pTD->pImgCtx->Disconnect();
}
if ( FAILED( hr ) && pTD->pImgCtx )
{
pTD->pImgCtx->Release();
pTD->pImgCtx = NULL;
}
*(pTD->pHr) = hr;
SetEvent( pTD->hEvent );
//
// Wait for the calling thread to finish up with IImgCtx before
// CoUninitialize gets called.
//
WaitForSingleObject(hExitThreadEvent, INFINITE);
CloseHandle(hExitThreadEvent);
CoUninitialize();
return 0;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CExtractIcon::SynchronousDownload ***
//
//
// Description:
// Synchronously downloads the image associated with the image context.
//
// Parameters:
// [In] szFile - The local (already in cache) file name of the
// image.
// [In] pIImgCtx - A pointer to the image context.
// [In] hExitThreadEvent - An event that gets signaled when the IImgCtx
// object is no longer in use.
//
// Return:
// S_OK if the image was successfully downloaded.
// E_FAIL if the image wasn't downloaded.
//
// Comments:
// The image context object doesn't directly support synchronous download.
// Here a message loop is used to make sure ulrmon keeps geeting messages
// and the download progresses.
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
CExtractIcon::SynchronousDownload(
LPCTSTR pszFile,
IImgCtx** ppIImgCtx,
HANDLE hExitThreadEvent
)
{
ASSERT(ppIImgCtx);
HRESULT hr;
TraceMsg(TF_CDFPARSE, "[*** IImgCtx downloading logo %s ***]",
pszFile);
TraceMsg(TF_CDFICON, "[*** IImgCtx downloading logo %s ***]",
pszFile);
WCHAR szFileW[MAX_PATH];
SHTCharToUnicode(pszFile, szFileW, ARRAYSIZE(szFileW));
ThreadData rgData;
rgData.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
if ( rgData.hEvent == NULL )
{
CloseHandle(hExitThreadEvent);
return E_OUTOFMEMORY;
}
rgData.hExitThreadEvent = hExitThreadEvent;
rgData.pszBuffer = szFileW;
rgData.pHr = &hr;
*ppIImgCtx = NULL;
if ( SHCreateThread( SyncDownloadThread, &rgData, 0, NULL ))
{
WaitForSingleObject( rgData.hEvent, INFINITE );
*ppIImgCtx = rgData.pImgCtx;
}
else
{
CloseHandle(hExitThreadEvent);
hr = E_OUTOFMEMORY;
}
CloseHandle( rgData.hEvent );
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CExtractIcon::ExtractImageIcon ***
//
//
// Description:
// Returns an HICON for the image in IImgCtx.
//
// Parameters:
// [In] wSize - The height and width of the icon,
// [In] pIImgCtx - The image to convert into an icon.
// [In] fDrawGleam - TRUE if a gleam should be added, FALSE otherwise.
//
// Return:
// An hicon of size nSize for the given IImgCtx.
// NULL on failure.
//
// Comments:
// Uses the image in IImgCtx to create bitmaps to pass to
// CreateIconIndirect.
//
////////////////////////////////////////////////////////////////////////////////
HICON
CExtractIcon::ExtractImageIcon(
WORD wSize,
IImgCtx* pIImgCtx,
BOOL fDrawGleam
)
{
ASSERT(pIImgCtx);
HICON hiconRet = NULL;
HDC hdcScreen = GetDC(NULL);
if (hdcScreen)
{
HBITMAP hbmImage = CreateCompatibleBitmap(hdcScreen, wSize, wSize);
if (hbmImage)
{
HBITMAP hbmMask = CreateBitmap(wSize, wSize, 1, 1, NULL);
if (hbmMask)
{
SIZE sz;
sz.cx = sz.cy = wSize;
if (SUCCEEDED(CreateImageAndMask(pIImgCtx, hdcScreen, &sz,
&hbmImage, &hbmMask,
fDrawGleam)))
{
ICONINFO ii;
ii.fIcon = TRUE;
ii.hbmMask = hbmMask;
ii.hbmColor = hbmImage;
hiconRet = CreateIconIndirect(&ii);
}
DeleteObject(hbmMask);
}
DeleteObject(hbmImage);
}
ReleaseDC(NULL, hdcScreen);
}
return hiconRet;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CExtractIcon::CreateImageAndMask ***
//
//
// Description:
// Create the image and mask bitmaps that get used by CreateIconIndirect,
//
// Parameters:
// [In] IImgCtx - The internet image.
// [In] hdcScreen - The screen hdc.
// [In] pSize - The size of the image and mask bitmaps.
// [In Out] phbmImage - A pointer to the handle of the Image bitmap.
// [In Out] phbmMask - A pointer to the handle of the Mask bitmap.
// [In] fDrawGleam - TRUE if a gleam should be added, FALSE otherwise.
//
// Return:
// S_OK if the image and mask bitmaps where successfully created.
// E_FAIL if the image or mask couldn't be created.
//
// Comments:
// The image bitmap has the opaque section come through and the transparent
// sections set to black.
//
// The mask has the transparent sections set to 1 and the opaque sections to
// 0.
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
CExtractIcon::CreateImageAndMask(
IImgCtx* pIImgCtx,
HDC hdcScreen,
SIZE* pSize,
HBITMAP* phbmImage,
HBITMAP* phbmMask,
BOOL fDrawGleam
)
{
ASSERT(pIImgCtx);
ASSERT(phbmImage);
ASSERT(phbmMask);
HRESULT hr = E_FAIL;
HDC hdcImgDst = CreateCompatibleDC(NULL);
if (hdcImgDst)
{
HGDIOBJ hbmOld = SelectObject(hdcImgDst, *phbmImage);
if (hbmOld)
{
if (ColorFill(hdcImgDst, pSize, COLOR1))
{
hr = StretchBltImage(pIImgCtx, pSize, hdcImgDst, fDrawGleam);
if (SUCCEEDED(hr))
{
hr = CreateMask(pIImgCtx, hdcScreen, hdcImgDst, pSize,
phbmMask, fDrawGleam);
}
}
SelectObject(hdcImgDst, hbmOld);
}
DeleteDC(hdcImgDst);
}
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CExtractIcon::StretchBltImage ***
//
//
// Description:
// Stretches the image associated with IImgCtx to the given size and places
// the result in the given DC.
//
// Parameters:
// [In] pIImgCtx - The image context for the image.
// [In] pSize - The size of the resultant image.
// [In/Out] hdcDst - The destination DC of the stretch blt.
//
// Return:
// S_OK if the image was successfully resized into the destination DC.
// E_FAIL otherwise.
//
// Comments:
// The destination DC already has a bitmap of pSize selected into it.
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
CExtractIcon::StretchBltImage(
IImgCtx* pIImgCtx,
const SIZE* pSize,
HDC hdcDst,
BOOL fDrawGleam
)
{
ASSERT(pIImgCtx);
ASSERT(hdcDst);
HRESULT hr;
SIZE sz;
ULONG fState;
hr = pIImgCtx->GetStateInfo(&fState, &sz, FALSE);
if (SUCCEEDED(hr))
{
hr = pIImgCtx->StretchBlt(hdcDst, 0, 0, pSize->cx, pSize->cy, 0, 0,
sz.cx, sz.cy, SRCCOPY);
ASSERT(SUCCEEDED(hr) && "Icon extraction pIImgCtx->StretchBlt failed!");
if (fDrawGleam)
{
hr = E_FAIL;
HANDLE hGleam = LoadImage(g_hinst, TEXT("ICONGLEAM"),
IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
if (hGleam)
{
if (DrawIconEx(hdcDst, 0, 0, (HICON)hGleam, pSize->cx, pSize->cy, 0, NULL,DI_NORMAL))
hr = S_OK;
DeleteObject(hGleam);
}
}
}
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CExtractIcon::CreateMask ***
//
//
// Description:
// Creates the mask for an icon and also adjusts the image bitmap for use
// with the mask.
//
// Parameters:
// [In] pIImgCtx - The original image.
// [In] hdcScreen - A screen dc.
// [In/Out] hdc1 - The DC containing the image bitmap.
// [In] pSize - The size of the bitmaps.
// [In/Out] phbMask - A pointer to the handle of the mask bitmap
//
// Return:
// S_OK if the mask is properly constructed.
// E_FAIL otherwise.
//
// Comments:
// The mask is created by first drawing the original image into a bitmap
// with background COLOR1. Then the same image is drawn into another
// bitmap but this bitmap has background of COLOR2. These two bitmaps
// are XOR'ed and the opaque sections come out 0 while the transparent
// sections are COLOR1 XOR COLOR2.
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
CExtractIcon::CreateMask(
IImgCtx* pIImgCtx,
HDC hdcScreen,
HDC hdc1,
const SIZE* pSize,
HBITMAP* phbMask,
BOOL fDrawGleam
)
{
ASSERT(hdc1);
ASSERT(pSize);
ASSERT(phbMask);
HRESULT hr = E_FAIL;
HDC hdc2 = CreateCompatibleDC(NULL);
if (hdc2)
{
HBITMAP hbm2 = CreateCompatibleBitmap(hdcScreen, pSize->cx, pSize->cy);
if (hbm2)
{
HGDIOBJ hbmOld2 = SelectObject(hdc2, hbm2);
if (hbmOld2)
{
ColorFill(hdc2, pSize, COLOR2);
hr = StretchBltImage(pIImgCtx, pSize, hdc2, fDrawGleam);
#ifndef UNIX
if (SUCCEEDED(hr) &&
BitBlt(hdc2, 0, 0, pSize->cx, pSize->cy, hdc1, 0, 0,
SRCINVERT))
{
if (GetDeviceCaps(hdcScreen, BITSPIXEL) <= 8)
{
//
// 6 is the XOR of the index for COLOR1 and the index
// for COLOR2.
//
SetBkColor(hdc2, PALETTEINDEX(6));
}
else
{
SetBkColor(hdc2, (COLORREF)(COLOR1 ^ COLOR2));
}
HDC hdcMask = CreateCompatibleDC(NULL);
if (hdcMask)
{
HGDIOBJ hbmOld = SelectObject(hdcMask, *phbMask);
if (hbmOld)
{
if (BitBlt(hdcMask, 0, 0, pSize->cx, pSize->cy, hdc2, 0,
0, SRCCOPY))
{
//
// RasterOP 0x00220326 does a copy of the ~mask bits
// of hdc1 and sets everything else to 0 (Black).
//
if (BitBlt(hdc1, 0, 0, pSize->cx, pSize->cy, hdcMask,
0, 0, 0x00220326))
{
hr = S_OK;
}
}
SelectObject(hdcMask, hbmOld);
}
DeleteDC(hdcMask);
}
}
#else
SetBkColor(hdc2, COLOR2);
HDC hdcMask = CreateCompatibleDC(NULL);
if (hdcMask)
{
HGDIOBJ hbmOld = SelectObject(hdcMask, *phbMask);
if (hbmOld)
{
if (BitBlt(hdcMask, 0, 0, pSize->cx, pSize->cy, hdc2, 0,
0, SRCCOPY))
{
//
// RasterOP 0x00220326 does a copy of the ~mask bits
// of hdc1 and sets everything else to 0 (Black).
//
if (BitBlt(hdc1, 0, 0, pSize->cx, pSize->cy, hdcMask,
0, 0, 0x00220326))
{
hr = S_OK;
}
}
SelectObject(hdcMask, hbmOld);
}
DeleteDC(hdcMask);
}
#endif /* UNIX */
SelectObject(hdc2, hbmOld2);
}
DeleteObject(hbm2);
}
DeleteDC(hdc2);
}
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** ImgCtx_Callback ***
//
//
// Description:
// Callback function for IImgCtx loads.
//
// Parameters:
// [In] pIImgCtx - Not Used.
// [Out] pfDone - Set to TRUE on this callback.
//
// Return:
// None.
//
// Comments:
// This callback gets called if IImgCtx is finished downloading an image.
// It is used in CExtractIcon and CIconHandler.
//
////////////////////////////////////////////////////////////////////////////////
void
CALLBACK
ImgCtx_Callback(
void* pIImgCtx,
void* pfDone
)
{
ASSERT(pfDone);
*(BOOL*)pfDone = TRUE;
return;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CExtractIcon::ColorFill ***
//
//
// Description:
// Fills the given bitmap with the given color.
//
// Parameters:
// [In/Out] hdc - The hdc that contains the bitmap.
// [In] pSize - the size of the bitmap.
// [In] clr - The color used to fill in the bitmap.
//
// Return:
// TRUE if the bitmap was filled with color clr.
// FALSE if the itmap wasn't filled.
//
////////////////////////////////////////////////////////////////////////////////
BOOL
CExtractIcon::ColorFill(
HDC hdc,
const SIZE* pSize,
COLORREF clr
)
{
ASSERT(hdc);
BOOL fRet = FALSE;
HBRUSH hbSolid = CreateSolidBrush(clr);
if (hbSolid)
{
HGDIOBJ hbOld = SelectObject(hdc, hbSolid);
if (hbOld)
{
PatBlt(hdc, 0, 0, pSize->cx, pSize->cy, PATCOPY);
fRet = TRUE;
SelectObject(hdc, hbOld);
}
DeleteObject(hbSolid);
}
return fRet;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CExtractIcon::ExtractGleamedIcon ***
//
//
// Description:
// Extracts icon resources and applies gleams to them.
//
// Parameters:
// [In] pszIconFile - path to the icon
// [In] iIndex - index of icon with the file
// [In] uFlags - ignore, pass 0
// [Out] phiconLarge - HICON in large format with gleam
// [Out] phiconSmall - HICON in small format with gleam
//
// Return:
// S_OK if success
// S_FALSE if the file has no icons (or not the asked for icon)
// E_FAIL for files on a slow link.
// E_FAIL if cant access the file
// E_FAIL if gleam icon construction failed
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
CExtractIcon::ExtractGleamedIcon(
LPCTSTR pszIconFile,
int iIndex,
UINT uFlags,
HICON *phiconLarge,
HICON *phiconSmall,
UINT nIconSize)
{
HICON hIconLargeShell, hIconSmallShell;
HRESULT hr;
hr = Priv_SHDefExtractIcon(pszIconFile, iIndex, uFlags,
&hIconLargeShell, &hIconSmallShell, nIconSize);
if (FAILED(hr))
goto cleanup1;
if (hIconLargeShell)
{
hr = ApplyGleamToIcon(hIconLargeShell, LOWORD(nIconSize), phiconLarge);
if (FAILED(hr))
goto cleanup2;
}
if (hIconSmallShell)
{
hr = ApplyGleamToIcon(hIconSmallShell, HIWORD(nIconSize), phiconSmall);
if (FAILED(hr))
goto cleanup3;
}
cleanup3:
if (FAILED(hr) && *phiconLarge)
{
DestroyIcon(*phiconLarge);
*phiconLarge = NULL;
}
cleanup2:
if (hIconLargeShell)
DestroyIcon(hIconLargeShell);
if (hIconSmallShell)
DestroyIcon(hIconSmallShell);
cleanup1:
return hr;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// *** CExtractIcon::ApplyGleamToIcon ***
//
//
// Description:
// Makes a gleamed version of an icon.
//
// Parameters:
// [In] hIcon - icon that needs to be gleamed
// [In] nSize - size of icon in pixels
// [Out] phGleamIcon - variable to contain the gleamed icon
//
//
// Return:
// S_OK if success
// E_FAIL if unsuccessful
//
////////////////////////////////////////////////////////////////////////////////
HRESULT
CExtractIcon::ApplyGleamToIcon(
HICON hIcon1,
ULONG nSize,
HICON *phGleamedIcon)
{
HRESULT hr = E_FAIL;
HICON hIcon2 = (HICON)LoadImage(g_hinst, TEXT("ICONGLEAM"), IMAGE_ICON,
nSize, nSize, 0);
if (hIcon2)
{
HDC dc = GetDC(NULL);
if (dc)
{
ICONINFO ii1, ii2;
if (GetIconInfo(hIcon1, &ii1) && GetIconInfo(hIcon2, &ii2))
{
HDC dcSrc = CreateCompatibleDC(dc);
if (dcSrc)
{
HDC dcDst = CreateCompatibleDC(dc);
if (dcDst)
{
HBITMAP bmMask = CreateBitmap(nSize, nSize, 1, 1, NULL);
if (bmMask)
{
HBITMAP bmImage = CreateCompatibleBitmap(dc, nSize,
nSize);
if (bmImage)
{
int cx1, cy1, cx2, cy2;
GetBitmapSize(ii1.hbmMask, &cx1, &cy1);
GetBitmapSize(ii2.hbmMask, &cx2, &cy2);
//
// Mask
//
HBITMAP hbmpOldDst = (HBITMAP)SelectObject(
dcDst,
bmMask);
HBITMAP hbmpOldSrc = (HBITMAP)SelectObject(
dcSrc,
ii1.hbmMask);
StretchBlt(dcDst, 0, 0, nSize, nSize, dcSrc, 0,
0, cx1, cy1, SRCCOPY);
SelectObject(dcSrc, ii2.hbmMask);
StretchBlt(dcDst, 0, 0, nSize, nSize, dcSrc, 0,
0, cx2, cy2, SRCAND);
//
// Image.
//
SelectObject(dcDst, bmImage);
SelectObject(dcSrc, ii1.hbmColor);
StretchBlt(dcDst, 0, 0, nSize, nSize, dcSrc, 0,
0, cx1, cy1, SRCCOPY);
SelectObject(dcSrc, ii2.hbmMask);
StretchBlt(dcDst, 0, 0, nSize, nSize, dcSrc, 0,
0, cx2, cy2, SRCAND);
SelectObject(dcSrc, ii2.hbmColor);
StretchBlt(dcDst, 0, 0, nSize, nSize, dcSrc, 0,
0, cx2, cy2, SRCINVERT);
ii1.hbmMask = bmMask;
ii1.hbmColor = bmImage;
*phGleamedIcon = CreateIconIndirect(&ii1);
if (*phGleamedIcon)
hr = S_OK;
SelectObject(dcSrc, hbmpOldSrc);
SelectObject(dcDst, hbmpOldDst);
DeleteObject(bmImage);
}
DeleteObject(bmMask);
}
DeleteDC(dcDst);
}
DeleteDC(dcSrc);
}
}
ReleaseDC(NULL, dc);
}
DestroyIcon(hIcon2);
}
return hr;
}
//
// Get the size of the given bitmap.
//
BOOL
CExtractIcon::GetBitmapSize(HBITMAP hbmp, int* pcx, int* pcy)
{
BOOL fRet;
BITMAP bm;
if (GetObject(hbmp, sizeof(bm), &bm))
{
*pcx = bm.bmWidth;
*pcy = bm.bmHeight;
fRet = TRUE;
}
else
{
fRet = FALSE;
}
return fRet;
}
//
// Replace '\' with '*' so the path is nolonger a recognized path name. This
// is done in-place and can be called multiple times on the same string.
//
void
MungePath(LPTSTR pszPath)
{
ASSERT(pszPath);
while(*pszPath)
{
if (TEXT(FILENAME_SEPARATOR) == *pszPath)
*pszPath = TEXT('*');
pszPath++;
}
return;
}
//
// Replace '*' with '\'.
//
void
DemungePath(LPTSTR pszPath)
{
ASSERT(pszPath);
while(*pszPath)
{
if (TEXT('*') == *pszPath)
*pszPath = TEXT(FILENAME_SEPARATOR);
pszPath++;
}
return;
}