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