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