|
|
#include "priv.h"
#include "strsafe.h"
HBITMAP CreateMirroredBitmap( HBITMAP hbmOrig) { HDC hdc, hdcMem1, hdcMem2; HBITMAP hbm = NULL, hOld_bm1, hOld_bm2; BITMAP bm; int IncOne = 0;
if (!hbmOrig) return NULL;
if (!GetObject(hbmOrig, sizeof(BITMAP), &bm)) return NULL;
// Grab the screen DC
hdc = GetDC(NULL);
if (hdc) { hdcMem1 = CreateCompatibleDC(hdc);
if (!hdcMem1) { ReleaseDC(NULL, hdc); return NULL; } hdcMem2 = CreateCompatibleDC(hdc); if (!hdcMem2) { DeleteDC(hdcMem1); ReleaseDC(NULL, hdc); return NULL; }
hbm = CreateCompatibleBitmap(hdc, bm.bmWidth, bm.bmHeight);
if (!hbm) { ReleaseDC(NULL, hdc); DeleteDC(hdcMem1); DeleteDC(hdcMem2); return NULL; }
//
// Flip the bitmap
//
hOld_bm1 = (HBITMAP)SelectObject(hdcMem1, hbmOrig); hOld_bm2 = (HBITMAP)SelectObject(hdcMem2 , hbm );
SET_DC_RTL_MIRRORED(hdcMem2); if (g_bRunOnMemphis) { // off-by-one on win98 or higher copying from non-mirrored to mirrored DC
IncOne++; }
BitBlt(hdcMem2, IncOne, 0, bm.bmWidth, bm.bmHeight, hdcMem1, 0, 0, SRCCOPY);
SelectObject(hdcMem1, hOld_bm1 ); SelectObject(hdcMem1, hOld_bm2 ); DeleteDC(hdcMem1); DeleteDC(hdcMem2);
ReleaseDC(NULL, hdc); }
return hbm; }
HICON CreateMirroredIcon(HICON hiconOrg) { HDC hdcScreen, hdcBitmap, hdcMask = NULL; HBITMAP hbm, hbmMask, hbmOld,hbmOldMask; BITMAP bm; ICONINFO ii; HICON hicon = NULL; #ifdef WINNT
#define IPIXELOFFSET 0
#else // !WINNT
#define IPIXELOFFSET 2
#endif WINNT
hdcBitmap = CreateCompatibleDC(NULL); if (hdcBitmap) { hdcMask = CreateCompatibleDC(NULL);
if( hdcMask ) {
SET_DC_RTL_MIRRORED(hdcBitmap); SET_DC_RTL_MIRRORED(hdcMask); } else { DeleteDC( hdcBitmap ); hdcBitmap = NULL; } } hdcScreen = GetDC(NULL);
if (hdcScreen) { if (hdcBitmap && hdcMask) { if (hiconOrg) { if (GetIconInfo(hiconOrg, &ii) && GetObject(ii.hbmColor, sizeof(BITMAP), &bm)) { //
// I don't want these.
//
DeleteObject( ii.hbmMask ); DeleteObject( ii.hbmColor ); ii.hbmMask = ii.hbmColor = NULL;
hbm = CreateCompatibleBitmap(hdcScreen, bm.bmWidth, bm.bmHeight); hbmMask = CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 1, NULL); hbmOld = (HBITMAP)SelectObject(hdcBitmap, hbm); hbmOldMask = (HBITMAP)SelectObject(hdcMask, hbmMask); DrawIconEx(hdcBitmap, IPIXELOFFSET, 0, hiconOrg, bm.bmWidth, bm.bmHeight, 0, NULL, DI_IMAGE);
DrawIconEx(hdcMask, IPIXELOFFSET, 0, hiconOrg, bm.bmWidth, bm.bmHeight, 0, NULL, DI_MASK);
SelectObject(hdcBitmap, hbmOld); SelectObject(hdcMask, hbmOldMask);
//
// create the new mirrored icon, and delete bmps
//
ii.hbmMask = hbmMask; ii.hbmColor = hbm; hicon = CreateIconIndirect(&ii);
DeleteObject(hbm); DeleteObject(hbmMask); } } }
ReleaseDC(NULL, hdcScreen); }
if (hdcBitmap) DeleteDC(hdcBitmap);
if (hdcMask) DeleteDC(hdcMask);
return hicon; }
HBITMAP AddImage_PrepareBitmap(LPCIMAGECACHEINFO pInfo, HBITMAP hbmp) { if (pInfo->dwMask & ICIFLAG_MIRROR) { return CreateMirroredBitmap(hbmp); } else { return hbmp; } }
HICON AddImage_PrepareIcon(LPCIMAGECACHEINFO pInfo, HICON hicon) { if (pInfo->dwMask & ICIFLAG_MIRROR) { return CreateMirroredIcon(hicon); } else { return hicon; } }
void AddImage_CleanupBitmap(LPCIMAGECACHEINFO pInfo, HBITMAP hbmp) { if (pInfo->dwMask & ICIFLAG_MIRROR) { if (hbmp) { DeleteObject(hbmp); } } }
void AddImage_CleanupIcon(LPCIMAGECACHEINFO pInfo, HICON hicon) { if (pInfo->dwMask & ICIFLAG_MIRROR) { if (hicon) { DestroyIcon(hicon); } } }
///////////////////////////////////////////////////////////////////////////////////
typedef struct { UINT uImageIndex; // The actual Image Index
// USAGE COUNT
UINT iUsage; // usage count....
DWORD dwUsage; // usage information
// SEARCH KEYS
DWORD dwFlags; // key: flags
int iIndex; // data: icon index
FILETIME ftDateStamp; WCHAR szName[1]; // the filename of the item....
} ICONCACHE_DATA, *PICONCACHE_DATA;
#define ICD_NOUSAGE 0x0001
#define ICD_DELETED 0x0002
#define ICD_SYSTEM 0x0004
class CImageListCache : public IImageCache3 { public: CImageListCache( void ); ~CImageListCache( void ); HRESULT Initialize ( void );
STDMETHOD ( QueryInterface )( REFIID riid, void ** ppv ); STDMETHOD_( ULONG, AddRef )( void ); STDMETHOD_( ULONG, Release )( void );
STDMETHOD ( AddImage )( LPCIMAGECACHEINFO pInfo, UINT * puImageIndex ); STDMETHOD ( FindImage )( LPCIMAGECACHEINFO pInfo, UINT * puImageIndex ); STDMETHOD ( FreeImage )( UINT iImageIndex ); STDMETHOD ( Flush )( BOOL fRelease ); STDMETHOD ( ChangeImageInfo )( UINT iImageIndex, LPCIMAGECACHEINFO pInfo ); STDMETHOD ( GetCacheSize )( UINT * puSize ); STDMETHOD ( GetUsage )( UINT iImageIndex, UINT * puUsage ); STDMETHOD ( GetImageList )( LPIMAGECACHEINITINFO pInfo );
STDMETHOD ( DeleteImage )( UINT iImageIndex ); STDMETHOD ( GetImageInfo )( UINT iImageIndex, LPIMAGECACHEINFO pInfo );
STDMETHOD ( GetImageIndexFromCacheIndex )( UINT iCacheIndex, UINT * puImageIndex );
protected: //internal methods.
UINT CountFreeSlots( void ); int FindEmptySlot( void ); ICONCACHE_DATA * CreateDataNode( LPCIMAGECACHEINFO pInfo ) const; ICONCACHE_DATA * GetNodeFromImageIndex( UINT iImageIndex ); UINT GetNodeIndexFromImageIndex( UINT iImageIndex );
HDPA m_hListData; HIMAGELIST m_himlLarge; HIMAGELIST m_himlSmall; CRITICAL_SECTION m_csLock; BOOL m_bLockInited; DWORD m_dwFlags; long m_cRef; };
STDAPI CImageListCache_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi) { HRESULT hr = E_OUTOFMEMORY; *ppunk = NULL;
CImageListCache * pCache = new CImageListCache(); if (pCache != NULL) { hr = pCache->Initialize(); if (SUCCEEDED(hr)) { *ppunk = SAFECAST(pCache, IImageCache *); } else { delete pCache; } }
return hr; }
STDMETHODIMP CImageListCache::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CImageListCache, IImageCache), QITABENT(CImageListCache, IImageCache2), QITABENT(CImageListCache, IImageCache3), { 0 }, }; return QISearch(this, qit, riid, ppv); }
STDMETHODIMP_(ULONG) CImageListCache::AddRef() { return InterlockedIncrement( &m_cRef ); }
STDMETHODIMP_(ULONG) CImageListCache::Release() { ASSERT( 0 != m_cRef ); ULONG cRef = InterlockedDecrement( &m_cRef ); if ( 0 == cRef ) { delete this; } return cRef; }
int CALLBACK DestroyEnum( void *p, void *pData ) { if ( p ) { LocalFree((ICONCACHE_DATA *) p); }
return TRUE; }
int CALLBACK UsageEnum( void *p, void *pData ) { ASSERT( p); ICONCACHE_DATA * pNode = (ICONCACHE_DATA *) p;
pNode->iUsage = PtrToUlong(pData); pNode->dwUsage = 0; return TRUE; }
CImageListCache::CImageListCache( ) { m_cRef = 1;
DllAddRef(); }
CImageListCache::~CImageListCache( ) { // don't bother entering the critical section, if we shouldn't be accessed
// by multiple threads if we have reached the destructor...
if ( m_himlLarge ) { ImageList_Destroy( m_himlLarge ); } if ( m_himlSmall ) { ImageList_Destroy( m_himlSmall ); }
if ( m_hListData ) { DPA_DestroyCallback( m_hListData, DestroyEnum, NULL ); m_hListData = NULL; }
if (m_bLockInited) { DeleteCriticalSection( &m_csLock ); }
DllRelease(); }
HRESULT CImageListCache::Initialize() { HRESULT hr = S_OK; __try { InitializeCriticalSection(&m_csLock); m_bLockInited = TRUE; } __except (EXCEPTION_EXECUTE_HANDLER) { hr = E_OUTOFMEMORY; } return hr; }
ICONCACHE_DATA * CImageListCache::CreateDataNode(LPCIMAGECACHEINFO pInfo ) const { UINT cbSize = sizeof( ICONCACHE_DATA ); UINT cbName = 0; if ( pInfo->dwMask & ICIFLAG_NAME ) { ASSERT( pInfo->pszName ); cbName = lstrlenW( pInfo->pszName ) * sizeof( WCHAR ); cbSize += cbName; // ICONCACHE_DATA defines szName as having one character already (for the NULL).
}
// zero init mem alloc
ICONCACHE_DATA * pNode = (ICONCACHE_DATA *) LocalAlloc( LPTR, cbSize ); if ( !pNode ) { return NULL; } // fill in the data...
if ( pInfo->dwMask & ICIFLAG_NAME ) { ASSERT(cbName); HRESULT hr = StringCbCopyW( pNode->szName, cbName + sizeof(WCHAR), pInfo->pszName ); ASSERT(SUCCEEDED(hr)); // This will not fail as we allocated enough memory above
} pNode->iIndex = pInfo->iIndex; pNode->dwFlags = pInfo->dwFlags; pNode->iUsage = 1; pNode->ftDateStamp = pInfo->ftDateStamp;
if ( pInfo->dwMask & ICIFLAG_NOUSAGE ) { pNode->dwUsage |= ICD_NOUSAGE; } if ( pInfo->dwMask & ICIFLAG_SYSTEM ) { pNode->dwUsage |= ICD_SYSTEM; }
return pNode; }
STDMETHODIMP CImageListCache::AddImage(LPCIMAGECACHEINFO pInfo, UINT * puImageIndex) { if ( !pInfo || !puImageIndex || !(pInfo->dwMask & (ICIFLAG_LARGE | ICIFLAG_SMALL)) || !(pInfo->dwMask & (ICIFLAG_BITMAP | ICIFLAG_ICON ))) { return E_INVALIDARG; }
ICONCACHE_DATA * pNode = CreateDataNode( pInfo ); if ( !pNode ) { return E_OUTOFMEMORY; }
EnterCriticalSection( &m_csLock ); int iImageIndex = -1; int iCacheIndex = FindEmptySlot(); if (iCacheIndex != -1) { // swap for the old one...
ICONCACHE_DATA * pOld = (ICONCACHE_DATA *) DPA_GetPtr( m_hListData, iCacheIndex ); if (m_dwFlags & ICIIFLAG_SORTBYUSED) { DPA_DeletePtr( m_hListData, iCacheIndex); DPA_AppendPtr( m_hListData, pNode); iImageIndex = pNode->uImageIndex = pOld->uImageIndex; } else { DPA_SetPtr( m_hListData, iCacheIndex, pNode); iImageIndex = pNode->uImageIndex = iCacheIndex; } // TraceMsg(TF_CUSTOM2, "CImageListCache::AddImage -- Replacing Image (CI:%d II:%d) ", iCacheIndex, iImageIndex);
LocalFree((LPVOID) pOld );
ASSERT(!(m_dwFlags & ICIIFLAG_LARGE) == !(pInfo->dwMask & ICIFLAG_LARGE) && !(m_dwFlags & ICIIFLAG_SMALL) == !(pInfo->dwMask & ICIFLAG_SMALL)); if ( pInfo->dwMask & ICIFLAG_LARGE ) { ASSERT( m_dwFlags & ICIIFLAG_LARGE ); if ( pInfo->dwMask & ICIFLAG_BITMAP ) { ASSERT( pInfo->hBitmapLarge );
HBITMAP hBitmapLarge = AddImage_PrepareBitmap(pInfo, pInfo->hBitmapLarge); HBITMAP hMaskLarge = AddImage_PrepareBitmap(pInfo, pInfo->hMaskLarge); ImageList_Replace( m_himlLarge, iImageIndex, hBitmapLarge, hMaskLarge ); AddImage_CleanupBitmap(pInfo, hBitmapLarge); AddImage_CleanupBitmap(pInfo, hMaskLarge); } else { ASSERT( pInfo->hIconLarge && pInfo->dwMask & ICIFLAG_ICON );
HICON hIconLarge = AddImage_PrepareIcon(pInfo, pInfo->hIconLarge); ImageList_ReplaceIcon( m_himlLarge, iImageIndex, hIconLarge ); AddImage_CleanupIcon(pInfo, hIconLarge); } } if ( pInfo->dwMask & ICIFLAG_SMALL ) { ASSERT( m_dwFlags & ICIIFLAG_SMALL ); if ( pInfo->dwMask & ICIFLAG_BITMAP ) { ASSERT( pInfo->hBitmapSmall );
HBITMAP hBitmapSmall = AddImage_PrepareBitmap(pInfo, pInfo->hBitmapSmall); HBITMAP hMaskSmall = AddImage_PrepareBitmap(pInfo, pInfo->hMaskSmall); ImageList_Replace( m_himlSmall, iImageIndex, hBitmapSmall, hMaskSmall ); AddImage_CleanupBitmap(pInfo, hBitmapSmall); AddImage_CleanupBitmap(pInfo, hMaskSmall); } else { ASSERT( pInfo->hIconSmall && pInfo->dwMask & ICIFLAG_ICON );
HICON hIconSmall = AddImage_PrepareIcon(pInfo, pInfo->hIconSmall); ImageList_ReplaceIcon( m_himlSmall, iImageIndex, hIconSmall ); AddImage_CleanupIcon(pInfo, hIconSmall); } } } else { iCacheIndex = DPA_AppendPtr( m_hListData, pNode ); if ( iCacheIndex >= 0 ) { if ( pInfo->dwMask & ICIFLAG_BITMAP ) { if ( pInfo->dwMask & ICIFLAG_LARGE ) { ASSERT( m_dwFlags & ICIIFLAG_LARGE ); ASSERT( pInfo->hBitmapLarge );
HBITMAP hBitmapLarge = AddImage_PrepareBitmap(pInfo, pInfo->hBitmapLarge); HBITMAP hMaskLarge = AddImage_PrepareBitmap(pInfo, pInfo->hMaskLarge); iImageIndex = ImageList_Add( m_himlLarge, hBitmapLarge, hMaskLarge); AddImage_CleanupBitmap(pInfo, hBitmapLarge); AddImage_CleanupBitmap(pInfo, hMaskLarge); } if ( pInfo->dwMask & ICIFLAG_SMALL ) { ASSERT( m_dwFlags & ICIIFLAG_SMALL ); ASSERT( pInfo->hBitmapSmall );
HBITMAP hBitmapSmall = AddImage_PrepareBitmap(pInfo, pInfo->hBitmapSmall); HBITMAP hMaskSmall = AddImage_PrepareBitmap(pInfo, pInfo->hMaskSmall); iImageIndex = ImageList_Add( m_himlSmall, hBitmapSmall, hMaskSmall); AddImage_CleanupBitmap(pInfo, hBitmapSmall); AddImage_CleanupBitmap(pInfo, hMaskSmall); } } else { ASSERT( pInfo->dwMask & ICIFLAG_ICON ); if ( pInfo->dwMask & ICIFLAG_LARGE ) { ASSERT( m_dwFlags & ICIIFLAG_LARGE ); ASSERT( pInfo->hIconLarge );
HICON hIconLarge = AddImage_PrepareIcon(pInfo, pInfo->hIconLarge); iImageIndex = ImageList_AddIcon( m_himlLarge, hIconLarge ); AddImage_CleanupIcon(pInfo, hIconLarge); } if ( pInfo->dwMask & ICIFLAG_SMALL ) { ASSERT( m_dwFlags & ICIIFLAG_SMALL ); ASSERT( pInfo->hIconSmall );
HICON hIconSmall = AddImage_PrepareIcon(pInfo, pInfo->hIconSmall); iImageIndex = ImageList_AddIcon( m_himlSmall, hIconSmall ); AddImage_CleanupIcon(pInfo, hIconSmall); } } ASSERT(iCacheIndex == iImageIndex); pNode->uImageIndex = iImageIndex; //TraceMsg(TF_CUSTOM2, "CImageListCache::AddImage -- Adding Image (CI:%d II:%d) ", iCacheIndex, iImageIndex);
} else { // failed to add to the list...
LocalFree( pNode ); } }
LeaveCriticalSection( &m_csLock ); *puImageIndex = (UINT) iImageIndex; return (iImageIndex >= 0) ? S_OK : E_OUTOFMEMORY; }
STDMETHODIMP CImageListCache::FindImage(LPCIMAGECACHEINFO pInfo, UINT *puImageIndex) { HRESULT hr = S_FALSE; ASSERT( m_hListData );
DWORD dwMatch = pInfo->dwMask & (ICIFLAG_FLAGS | ICIFLAG_NAME | ICIFLAG_INDEX | ICIFLAG_DATESTAMP); DWORD dwMask; int iCacheIndex = 0; ICONCACHE_DATA * pNode = NULL; EnterCriticalSection( &m_csLock ); do { dwMask = 0; pNode = (ICONCACHE_DATA *) DPA_GetPtr( m_hListData, iCacheIndex ); if ( !pNode ) { break; }
if ((pNode->dwUsage & ICD_DELETED) || (pNode->iUsage == 0)) { iCacheIndex ++; continue; } if (( dwMatch & ICIFLAG_NAME ) && StrCmpW( pInfo->pszName, pNode->szName ) == 0 ) { // found it
dwMask |= ICIFLAG_NAME; } if (( dwMatch& ICIFLAG_INDEX ) && pInfo->iIndex == pNode->iIndex ) { dwMask |= ICIFLAG_INDEX; } if (( dwMatch & ICIFLAG_FLAGS ) && pInfo->dwFlags == pNode->dwFlags ) { dwMask |= ICIFLAG_FLAGS; }
if (( dwMatch & ICIFLAG_DATESTAMP ) && ( pInfo->ftDateStamp.dwLowDateTime == pNode->ftDateStamp.dwLowDateTime && pInfo->ftDateStamp.dwHighDateTime == pNode->ftDateStamp.dwHighDateTime )) { dwMask |= ICIFLAG_DATESTAMP; }
iCacheIndex ++; } while ( dwMask != dwMatch);
// found it, save the index... (as long as it was freed not deleted...
if ( pNode && (dwMask == dwMatch) ) { //TraceMsg(TF_CUSTOM2, "CImageListCache::FindImage *FOUND* (path=%s)", pNode->szName);
hr = S_OK; *puImageIndex = (UINT) pNode->uImageIndex; // bump usage
iCacheIndex --; // We had an extra increment at the end.
if ( !(pNode->dwUsage & ICD_SYSTEM) ) { if (m_dwFlags & ICIIFLAG_SORTBYUSED) { DPA_DeletePtr(m_hListData, iCacheIndex); iCacheIndex = DPA_AppendPtr(m_hListData, pNode); if (iCacheIndex == -1) // We failed to move the node...
{ LocalFree(pNode); *puImageIndex = (UINT) -1; hr = E_OUTOFMEMORY; } } else if ( !(pNode->dwUsage) && !(pInfo->dwMask & ICIFLAG_NOUSAGE )) { ASSERT(!(pNode->dwUsage & ICD_DELETED)); pNode->iUsage++; } } } LeaveCriticalSection( &m_csLock );
return hr; }
STDMETHODIMP CImageListCache::Flush(BOOL fRelease) { ASSERT( m_hListData );
EnterCriticalSection( &m_csLock ); if ( fRelease ) { // simply empty the data list. The ImageList never shrinks...
DPA_EnumCallback( m_hListData, DestroyEnum, NULL ); DPA_DeleteAllPtrs( m_hListData );
if ( m_himlLarge ) { ImageList_RemoveAll( m_himlLarge ); }
if ( m_himlSmall ) { ImageList_RemoveAll( m_himlSmall ); } } else { DPA_EnumCallback( m_hListData, UsageEnum, 0 ); } LeaveCriticalSection( &m_csLock );
return S_OK; }
STDMETHODIMP CImageListCache::FreeImage(UINT uImageIndex) { ASSERT ( m_hListData ); HRESULT hr = E_INVALIDARG;
EnterCriticalSection(&m_csLock); ICONCACHE_DATA * pNode = GetNodeFromImageIndex(uImageIndex); if (pNode) { if (!pNode->dwUsage && pNode->iUsage) { hr = S_OK; if (m_dwFlags & ICIIFLAG_SORTBYUSED) { //TraceMsg(TF_CUSTOM2, "CImageListCache::FreeImage -- (CI::%d II::%d)", GetNodeIndexFromImageIndex(uImageIndex), uImageIndex);
pNode->iUsage = 0; } else { pNode->iUsage--; } } else { hr = S_FALSE; } }
LeaveCriticalSection(&m_csLock); return hr; }
STDMETHODIMP CImageListCache::DeleteImage(UINT uImageIndex) { HRESULT hr = E_INVALIDARG; ASSERT ( m_hListData );
EnterCriticalSection( &m_csLock ); ICONCACHE_DATA * pNode = GetNodeFromImageIndex(uImageIndex); if (pNode) { if ( !pNode->dwUsage ) { pNode->dwUsage = ICD_DELETED; hr = S_OK; } else { hr = S_FALSE; } }
LeaveCriticalSection( &m_csLock ); return hr; }
STDMETHODIMP CImageListCache::ChangeImageInfo(UINT uImageIndex, LPCIMAGECACHEINFO pInfo) { ASSERT( m_hListData ); EnterCriticalSection( &m_csLock ); UINT uCacheIndex = GetNodeIndexFromImageIndex(uImageIndex); if (-1 == uCacheIndex) { LeaveCriticalSection( &m_csLock ); return E_INVALIDARG; } ICONCACHE_DATA * pNode = CreateDataNode( pInfo ); if (!pNode) { LeaveCriticalSection( &m_csLock ); return E_OUTOFMEMORY; }
ICONCACHE_DATA * pOld = (ICONCACHE_DATA *) DPA_GetPtr( m_hListData, uCacheIndex ); ASSERT( pOld ); DPA_SetPtr( m_hListData, uCacheIndex, pNode ); pNode->iUsage = pOld->iUsage; pNode->dwUsage = pOld->dwUsage; pNode->uImageIndex = pOld->uImageIndex; LocalFree( pOld );
if ( pInfo->dwMask & ( ICIFLAG_BITMAP | ICIFLAG_ICON )) { // update the picture....
if ( pInfo->dwMask & ICIFLAG_LARGE ) { if ( pInfo->dwMask & ICIFLAG_BITMAP ) { ASSERT( pInfo->hBitmapLarge ); ImageList_Replace( m_himlLarge, uImageIndex, pInfo->hBitmapLarge, pInfo->hMaskLarge ); } else { ASSERT( pInfo->hIconLarge && pInfo->dwMask & ICIFLAG_ICON ); ImageList_ReplaceIcon( m_himlLarge, uImageIndex, pInfo->hIconLarge ); } } if ( pInfo->dwMask & ICIFLAG_SMALL ) { if ( pInfo->dwMask & ICIFLAG_BITMAP ) { ASSERT( pInfo->hBitmapSmall ); ImageList_Replace( m_himlSmall, uImageIndex, pInfo->hBitmapSmall, pInfo->hMaskSmall ); } else { ASSERT( pInfo->hIconSmall && pInfo->dwMask & ICIFLAG_ICON ); ImageList_ReplaceIcon( m_himlLarge, uImageIndex, pInfo->hIconSmall ); } } } LeaveCriticalSection(&m_csLock); return S_OK; }
UINT CImageListCache::CountFreeSlots( ) { ASSERT( m_hListData ); int iSlot = 0; UINT uFree = 0; do { ICONCACHE_DATA * pNode = (ICONCACHE_DATA *) DPA_GetPtr( m_hListData, iSlot ++ ); if ( !pNode ) { break; }
if (pNode->iUsage == 0 || (pNode->dwUsage & ICD_DELETED)) { uFree++; } } while ( TRUE );
return uFree; }
STDMETHODIMP CImageListCache::GetCacheSize(UINT * puSize) { ASSERT( m_hListData );
EnterCriticalSection( &m_csLock ); *puSize = DPA_GetPtrCount( m_hListData ) - CountFreeSlots(); LeaveCriticalSection( &m_csLock ); return S_OK; }
STDMETHODIMP CImageListCache::GetImageList(LPIMAGECACHEINITINFO pInfo ) { ASSERT( pInfo->cbSize == sizeof( IMAGECACHEINITINFO ));
if ( !(pInfo->dwMask & (ICIIFLAG_LARGE | ICIIFLAG_SMALL))) { // must specify one or both of large or small
return E_INVALIDARG; }
if ( m_hListData ) { // we have already been created, just pass back the info if they match.....
if ((( pInfo->dwMask & ICIIFLAG_SMALL ) && !m_himlSmall ) || (( pInfo->dwMask & ICIIFLAG_LARGE ) && !m_himlLarge ) || ( m_dwFlags != pInfo->dwMask )) { return E_INVALIDARG; }
if ( pInfo->dwMask & ICIIFLAG_SMALL ) { pInfo->himlSmall = m_himlSmall; } if ( pInfo->dwMask & ICIIFLAG_LARGE ) { pInfo->himlLarge = m_himlLarge; }
return S_FALSE; } m_hListData = DPA_Create( 30 ); if ( !m_hListData ) { return E_OUTOFMEMORY; } if ( pInfo->dwMask & ICIIFLAG_LARGE ) { m_himlLarge = ImageList_Create( pInfo->rgSizeLarge.cx, pInfo->rgSizeLarge.cy, pInfo->dwFlags, pInfo->iStart, pInfo->iGrow ); if ( !m_himlLarge ) { return E_OUTOFMEMORY; } pInfo->himlLarge = m_himlLarge; } if ( pInfo->dwMask & ICIIFLAG_SMALL ) { m_himlSmall = ImageList_Create( pInfo->rgSizeSmall.cx, pInfo->rgSizeSmall.cy, pInfo->dwFlags, pInfo->iStart, pInfo->iGrow ); if ( !m_himlSmall ) { return E_OUTOFMEMORY; } pInfo->himlSmall = m_himlSmall; }
m_dwFlags = pInfo->dwMask; return S_OK; }
int CImageListCache::FindEmptySlot() { // search for an element with a zero usage count...
ASSERT( m_hListData ); int iCacheIndex = 0; do { ICONCACHE_DATA * pNode = (ICONCACHE_DATA *) DPA_GetPtr( m_hListData, iCacheIndex ); if ( !pNode ) { break; }
if (pNode->iUsage == 0 || (pNode->dwUsage & ICD_DELETED)) { return iCacheIndex; } iCacheIndex ++; } while (TRUE); return -1; }
STDMETHODIMP CImageListCache::GetUsage(UINT uImageIndex, UINT * puUsage) { ASSERT( m_hListData );
EnterCriticalSection( &m_csLock );
HRESULT hr = E_INVALIDARG; ICONCACHE_DATA * pNode = GetNodeFromImageIndex(uImageIndex); if (pNode) { if (pNode->dwUsage & ICD_DELETED) { *puUsage = ICD_USAGE_DELETED; } else if (pNode->dwUsage & ICD_SYSTEM) { *puUsage = ICD_USAGE_SYSTEM; } else if (pNode->dwUsage & ICD_NOUSAGE) { *puUsage = ICD_USAGE_NOUSAGE; } else { *puUsage = pNode->iUsage; } hr = S_OK; }
LeaveCriticalSection( &m_csLock ); return hr; }
STDMETHODIMP CImageListCache::GetImageInfo(UINT uImageIndex, LPIMAGECACHEINFO pInfo) { HRESULT hr; ASSERT( m_hListData );
EnterCriticalSection( &m_csLock ); ICONCACHE_DATA * pNode = GetNodeFromImageIndex(uImageIndex); if (pNode) { hr = E_NOTIMPL; if ( pInfo->dwMask & ICIFLAG_DATESTAMP ) { if ( pNode->dwFlags & ICIFLAG_DATESTAMP ) { pInfo->ftDateStamp = pNode->ftDateStamp; hr = S_OK; } else { hr = E_FAIL; } }
if ( pInfo->dwMask & ICIFLAG_NOUSAGE ) { hr = S_OK; } pInfo->dwMask = pNode->dwFlags & pInfo->dwMask; } else hr = E_INVALIDARG; LeaveCriticalSection(&m_csLock); return hr; }
STDMETHODIMP CImageListCache::GetImageIndexFromCacheIndex( UINT iCacheIndex, UINT * puImageIndex ) { ASSERT( m_hListData ); HRESULT hr = E_INVALIDARG; EnterCriticalSection( &m_csLock ); ICONCACHE_DATA *pNode = (ICONCACHE_DATA *) DPA_GetPtr( m_hListData, iCacheIndex ); *puImageIndex = (UINT) -1; if (pNode) { *puImageIndex = (UINT) pNode->uImageIndex; hr = S_OK; }
LeaveCriticalSection(&m_csLock); return hr; }
ICONCACHE_DATA * CImageListCache::GetNodeFromImageIndex( UINT iImageIndex ) { UINT iCacheIndex = GetNodeIndexFromImageIndex(iImageIndex); return (iCacheIndex == -1) ? NULL : (ICONCACHE_DATA *) DPA_GetPtr( m_hListData, iCacheIndex ); }
UINT CImageListCache::GetNodeIndexFromImageIndex( UINT iImageIndex ) { UINT iCacheIndex = 0; ICONCACHE_DATA * pNode = NULL;
// We must assume that we have the critical section here or else the data would be
// meaningless upon return from this function.
do { pNode = (ICONCACHE_DATA *) DPA_GetPtr( m_hListData, iCacheIndex ); if ( !pNode ) { break; }
if (pNode->dwUsage & ICD_DELETED) { iCacheIndex ++; continue; }
iCacheIndex ++; } while ( pNode->uImageIndex != iImageIndex );
return (pNode ? iCacheIndex - 1 : -1); }
|