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.

1038 lines
28 KiB

  1. #include "priv.h"
  2. HBITMAP CreateMirroredBitmap( HBITMAP hbmOrig)
  3. {
  4. HDC hdc, hdcMem1, hdcMem2;
  5. HBITMAP hbm = NULL, hOld_bm1, hOld_bm2;
  6. BITMAP bm;
  7. int IncOne = 0;
  8. if (!hbmOrig)
  9. return NULL;
  10. if (!GetObject(hbmOrig, sizeof(BITMAP), &bm))
  11. return NULL;
  12. // Grab the screen DC
  13. hdc = GetDC(NULL);
  14. if (hdc)
  15. {
  16. hdcMem1 = CreateCompatibleDC(hdc);
  17. if (!hdcMem1)
  18. {
  19. ReleaseDC(NULL, hdc);
  20. return NULL;
  21. }
  22. hdcMem2 = CreateCompatibleDC(hdc);
  23. if (!hdcMem2)
  24. {
  25. DeleteDC(hdcMem1);
  26. ReleaseDC(NULL, hdc);
  27. return NULL;
  28. }
  29. hbm = CreateCompatibleBitmap(hdc, bm.bmWidth, bm.bmHeight);
  30. if (!hbm)
  31. {
  32. ReleaseDC(NULL, hdc);
  33. DeleteDC(hdcMem1);
  34. DeleteDC(hdcMem2);
  35. return NULL;
  36. }
  37. //
  38. // Flip the bitmap
  39. //
  40. hOld_bm1 = (HBITMAP)SelectObject(hdcMem1, hbmOrig);
  41. hOld_bm2 = (HBITMAP)SelectObject(hdcMem2 , hbm );
  42. SET_DC_RTL_MIRRORED(hdcMem2);
  43. if (g_bRunOnMemphis)
  44. {
  45. // off-by-one on win98 or higher copying from non-mirrored to mirrored DC
  46. IncOne++;
  47. }
  48. BitBlt(hdcMem2, IncOne, 0, bm.bmWidth, bm.bmHeight, hdcMem1, 0, 0, SRCCOPY);
  49. SelectObject(hdcMem1, hOld_bm1 );
  50. SelectObject(hdcMem1, hOld_bm2 );
  51. DeleteDC(hdcMem1);
  52. DeleteDC(hdcMem2);
  53. ReleaseDC(NULL, hdc);
  54. }
  55. return hbm;
  56. }
  57. HICON CreateMirroredIcon(HICON hiconOrg)
  58. {
  59. HDC hdcScreen, hdcBitmap, hdcMask = NULL;
  60. HBITMAP hbm, hbmMask, hbmOld,hbmOldMask;
  61. BITMAP bm;
  62. ICONINFO ii;
  63. HICON hicon = NULL;
  64. #ifdef WINNT
  65. #define IPIXELOFFSET 0
  66. #else // !WINNT
  67. #define IPIXELOFFSET 2
  68. #endif WINNT
  69. hdcBitmap = CreateCompatibleDC(NULL);
  70. if (hdcBitmap)
  71. {
  72. hdcMask = CreateCompatibleDC(NULL);
  73. if( hdcMask )
  74. {
  75. SET_DC_RTL_MIRRORED(hdcBitmap);
  76. SET_DC_RTL_MIRRORED(hdcMask);
  77. }
  78. else
  79. {
  80. DeleteDC( hdcBitmap );
  81. hdcBitmap = NULL;
  82. }
  83. }
  84. hdcScreen = GetDC(NULL);
  85. if (hdcScreen)
  86. {
  87. if (hdcBitmap && hdcMask)
  88. {
  89. if (hiconOrg)
  90. {
  91. if (GetIconInfo(hiconOrg, &ii) &&
  92. GetObject(ii.hbmColor, sizeof(BITMAP), &bm))
  93. {
  94. //
  95. // I don't want these.
  96. //
  97. DeleteObject( ii.hbmMask );
  98. DeleteObject( ii.hbmColor );
  99. ii.hbmMask = ii.hbmColor = NULL;
  100. hbm = CreateCompatibleBitmap(hdcScreen, bm.bmWidth, bm.bmHeight);
  101. hbmMask = CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 1, NULL);
  102. hbmOld = (HBITMAP)SelectObject(hdcBitmap, hbm);
  103. hbmOldMask = (HBITMAP)SelectObject(hdcMask, hbmMask);
  104. DrawIconEx(hdcBitmap, IPIXELOFFSET, 0, hiconOrg, bm.bmWidth, bm.bmHeight, 0,
  105. NULL, DI_IMAGE);
  106. DrawIconEx(hdcMask, IPIXELOFFSET, 0, hiconOrg, bm.bmWidth, bm.bmHeight, 0,
  107. NULL, DI_MASK);
  108. SelectObject(hdcBitmap, hbmOld);
  109. SelectObject(hdcMask, hbmOldMask);
  110. //
  111. // create the new mirrored icon, and delete bmps
  112. //
  113. ii.hbmMask = hbmMask;
  114. ii.hbmColor = hbm;
  115. hicon = CreateIconIndirect(&ii);
  116. DeleteObject(hbm);
  117. DeleteObject(hbmMask);
  118. }
  119. }
  120. }
  121. ReleaseDC(NULL, hdcScreen);
  122. }
  123. if (hdcBitmap)
  124. DeleteDC(hdcBitmap);
  125. if (hdcMask)
  126. DeleteDC(hdcMask);
  127. return hicon;
  128. }
  129. HBITMAP AddImage_PrepareBitmap(LPCIMAGECACHEINFO pInfo, HBITMAP hbmp)
  130. {
  131. if (pInfo->dwMask & ICIFLAG_MIRROR)
  132. {
  133. return CreateMirroredBitmap(hbmp);
  134. }
  135. else
  136. {
  137. return hbmp;
  138. }
  139. }
  140. HICON AddImage_PrepareIcon(LPCIMAGECACHEINFO pInfo, HICON hicon)
  141. {
  142. if (pInfo->dwMask & ICIFLAG_MIRROR)
  143. {
  144. return CreateMirroredIcon(hicon);
  145. }
  146. else
  147. {
  148. return hicon;
  149. }
  150. }
  151. void AddImage_CleanupBitmap(LPCIMAGECACHEINFO pInfo, HBITMAP hbmp)
  152. {
  153. if (pInfo->dwMask & ICIFLAG_MIRROR)
  154. {
  155. if (hbmp)
  156. {
  157. DeleteObject(hbmp);
  158. }
  159. }
  160. }
  161. void AddImage_CleanupIcon(LPCIMAGECACHEINFO pInfo, HICON hicon)
  162. {
  163. if (pInfo->dwMask & ICIFLAG_MIRROR)
  164. {
  165. if (hicon)
  166. {
  167. DestroyIcon(hicon);
  168. }
  169. }
  170. }
  171. ///////////////////////////////////////////////////////////////////////////////////
  172. typedef struct
  173. {
  174. UINT uImageIndex; // The actual Image Index
  175. // USAGE COUNT
  176. UINT iUsage; // usage count....
  177. DWORD dwUsage; // usage information
  178. // SEARCH KEYS
  179. DWORD dwFlags; // key: flags
  180. int iIndex; // data: icon index
  181. FILETIME ftDateStamp;
  182. WCHAR szName[1]; // the filename of the item....
  183. } ICONCACHE_DATA, *PICONCACHE_DATA;
  184. #define ICD_NOUSAGE 0x0001
  185. #define ICD_DELETED 0x0002
  186. #define ICD_SYSTEM 0x0004
  187. class CImageListCache : public IImageCache3
  188. {
  189. public:
  190. CImageListCache( void );
  191. ~CImageListCache( void );
  192. STDMETHOD ( QueryInterface )( REFIID riid, void ** ppv );
  193. STDMETHOD_( ULONG, AddRef )( void );
  194. STDMETHOD_( ULONG, Release )( void );
  195. STDMETHOD ( AddImage )( LPCIMAGECACHEINFO pInfo, UINT * puImageIndex );
  196. STDMETHOD ( FindImage )( LPCIMAGECACHEINFO pInfo, UINT * puImageIndex );
  197. STDMETHOD ( FreeImage )( UINT iImageIndex );
  198. STDMETHOD ( Flush )( BOOL fRelease );
  199. STDMETHOD ( ChangeImageInfo )( UINT iImageIndex, LPCIMAGECACHEINFO pInfo );
  200. STDMETHOD ( GetCacheSize )( UINT * puSize );
  201. STDMETHOD ( GetUsage )( UINT iImageIndex, UINT * puUsage );
  202. STDMETHOD ( GetImageList )( LPIMAGECACHEINITINFO pInfo );
  203. STDMETHOD ( DeleteImage )( UINT iImageIndex );
  204. STDMETHOD ( GetImageInfo )( UINT iImageIndex, LPIMAGECACHEINFO pInfo );
  205. STDMETHOD ( GetImageIndexFromCacheIndex )( UINT iCacheIndex, UINT * puImageIndex );
  206. protected: //internal methods.
  207. UINT CountFreeSlots( void );
  208. int FindEmptySlot( void );
  209. ICONCACHE_DATA * CreateDataNode( LPCIMAGECACHEINFO pInfo ) const;
  210. ICONCACHE_DATA * GetNodeFromImageIndex( UINT iImageIndex );
  211. UINT GetNodeIndexFromImageIndex( UINT iImageIndex );
  212. HDPA m_hListData;
  213. HIMAGELIST m_himlLarge;
  214. HIMAGELIST m_himlSmall;
  215. CRITICAL_SECTION m_csLock;
  216. DWORD m_dwFlags;
  217. long m_cRef;
  218. };
  219. STDAPI CImageListCache_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  220. {
  221. *ppunk = NULL;
  222. CImageListCache * pCache = new CImageListCache();
  223. if (pCache != NULL)
  224. {
  225. *ppunk = SAFECAST(pCache, IImageCache *);
  226. return S_OK;
  227. }
  228. return E_OUTOFMEMORY;
  229. }
  230. STDMETHODIMP CImageListCache::QueryInterface(REFIID riid, void **ppv)
  231. {
  232. static const QITAB qit[] = {
  233. QITABENT(CImageListCache, IImageCache),
  234. QITABENT(CImageListCache, IImageCache2),
  235. QITABENT(CImageListCache, IImageCache3),
  236. { 0 },
  237. };
  238. return QISearch(this, qit, riid, ppv);
  239. }
  240. STDMETHODIMP_(ULONG) CImageListCache::AddRef()
  241. {
  242. InterlockedIncrement( &m_cRef );
  243. return m_cRef;
  244. }
  245. STDMETHODIMP_(ULONG) CImageListCache::Release()
  246. {
  247. if (InterlockedDecrement( &m_cRef ))
  248. return m_cRef;
  249. delete this;
  250. return 0;
  251. }
  252. int CALLBACK DestroyEnum( void *p, void *pData )
  253. {
  254. ASSERT( p );
  255. if ( p )
  256. {
  257. LocalFree((ICONCACHE_DATA *) p);
  258. }
  259. return TRUE;
  260. }
  261. int CALLBACK UsageEnum( void *p, void *pData )
  262. {
  263. ASSERT( p);
  264. ICONCACHE_DATA * pNode = (ICONCACHE_DATA *) p;
  265. pNode->iUsage = PtrToUlong(pData);
  266. pNode->dwUsage = 0;
  267. return TRUE;
  268. }
  269. CImageListCache::CImageListCache( )
  270. {
  271. // imagelist info.
  272. InitializeCriticalSection( &m_csLock );
  273. m_cRef = 1;
  274. DllAddRef();
  275. }
  276. CImageListCache::~CImageListCache( )
  277. {
  278. // don't bother entering the critical section, if we shouldn't be accessed
  279. // by multiple threads if we have reached the destructor...
  280. if ( m_himlLarge )
  281. {
  282. ImageList_Destroy( m_himlLarge );
  283. }
  284. if ( m_himlSmall )
  285. {
  286. ImageList_Destroy( m_himlSmall );
  287. }
  288. if ( m_hListData )
  289. {
  290. DPA_DestroyCallback( m_hListData, DestroyEnum, NULL );
  291. m_hListData = NULL;
  292. }
  293. DeleteCriticalSection( &m_csLock );
  294. DllRelease();
  295. }
  296. ICONCACHE_DATA * CImageListCache::CreateDataNode(LPCIMAGECACHEINFO pInfo ) const
  297. {
  298. UINT cbSize = sizeof( ICONCACHE_DATA );
  299. if ( pInfo->dwMask & ICIFLAG_NAME )
  300. {
  301. ASSERT( pInfo->pszName );
  302. cbSize += lstrlenW( pInfo->pszName ) * sizeof( WCHAR );
  303. }
  304. // zero init mem alloc
  305. ICONCACHE_DATA * pNode = (ICONCACHE_DATA *) LocalAlloc( LPTR, cbSize );
  306. if ( !pNode )
  307. {
  308. return NULL;
  309. }
  310. // fill in the data...
  311. if ( pInfo->dwMask & ICIFLAG_NAME )
  312. {
  313. StrCpyW( pNode->szName, pInfo->pszName );
  314. }
  315. pNode->iIndex = pInfo->iIndex;
  316. pNode->dwFlags = pInfo->dwFlags;
  317. pNode->iUsage = 1;
  318. pNode->ftDateStamp = pInfo->ftDateStamp;
  319. if ( pInfo->dwMask & ICIFLAG_NOUSAGE )
  320. {
  321. pNode->dwUsage |= ICD_NOUSAGE;
  322. }
  323. if ( pInfo->dwMask & ICIFLAG_SYSTEM )
  324. {
  325. pNode->dwUsage |= ICD_SYSTEM;
  326. }
  327. return pNode;
  328. }
  329. STDMETHODIMP CImageListCache::AddImage(LPCIMAGECACHEINFO pInfo, UINT * puImageIndex)
  330. {
  331. if ( !pInfo || !puImageIndex || !(pInfo->dwMask & (ICIFLAG_LARGE | ICIFLAG_SMALL)) ||
  332. !(pInfo->dwMask & (ICIFLAG_BITMAP | ICIFLAG_ICON )))
  333. {
  334. return E_INVALIDARG;
  335. }
  336. ICONCACHE_DATA * pNode = CreateDataNode( pInfo );
  337. if ( !pNode )
  338. {
  339. return E_OUTOFMEMORY;
  340. }
  341. EnterCriticalSection( &m_csLock );
  342. int iImageIndex = -1;
  343. int iCacheIndex = FindEmptySlot();
  344. if (iCacheIndex != -1)
  345. {
  346. // swap for the old one...
  347. ICONCACHE_DATA * pOld = (ICONCACHE_DATA *) DPA_GetPtr( m_hListData, iCacheIndex );
  348. if (m_dwFlags & ICIIFLAG_SORTBYUSED)
  349. {
  350. DPA_DeletePtr( m_hListData, iCacheIndex);
  351. DPA_AppendPtr( m_hListData, pNode);
  352. iImageIndex = pNode->uImageIndex = pOld->uImageIndex;
  353. }
  354. else
  355. {
  356. DPA_SetPtr( m_hListData, iCacheIndex, pNode);
  357. iImageIndex = pNode->uImageIndex = iCacheIndex;
  358. }
  359. // TraceMsg(TF_CUSTOM2, "CImageListCache::AddImage -- Replacing Image (CI:%d II:%d) ", iCacheIndex, iImageIndex);
  360. LocalFree((LPVOID) pOld );
  361. ASSERT(!(m_dwFlags & ICIIFLAG_LARGE) == !(pInfo->dwMask & ICIFLAG_LARGE)
  362. && !(m_dwFlags & ICIIFLAG_SMALL) == !(pInfo->dwMask & ICIFLAG_SMALL));
  363. if ( pInfo->dwMask & ICIFLAG_LARGE )
  364. {
  365. ASSERT( m_dwFlags & ICIIFLAG_LARGE );
  366. if ( pInfo->dwMask & ICIFLAG_BITMAP )
  367. {
  368. ASSERT( pInfo->hBitmapLarge );
  369. HBITMAP hBitmapLarge = AddImage_PrepareBitmap(pInfo, pInfo->hBitmapLarge);
  370. HBITMAP hMaskLarge = AddImage_PrepareBitmap(pInfo, pInfo->hMaskLarge);
  371. ImageList_Replace( m_himlLarge, iImageIndex, hBitmapLarge, hMaskLarge );
  372. AddImage_CleanupBitmap(pInfo, hBitmapLarge);
  373. AddImage_CleanupBitmap(pInfo, hMaskLarge);
  374. }
  375. else
  376. {
  377. ASSERT( pInfo->hIconLarge && pInfo->dwMask & ICIFLAG_ICON );
  378. HICON hIconLarge = AddImage_PrepareIcon(pInfo, pInfo->hIconLarge);
  379. ImageList_ReplaceIcon( m_himlLarge, iImageIndex, hIconLarge );
  380. AddImage_CleanupIcon(pInfo, hIconLarge);
  381. }
  382. }
  383. if ( pInfo->dwMask & ICIFLAG_SMALL )
  384. {
  385. ASSERT( m_dwFlags & ICIIFLAG_SMALL );
  386. if ( pInfo->dwMask & ICIFLAG_BITMAP )
  387. {
  388. ASSERT( pInfo->hBitmapSmall );
  389. HBITMAP hBitmapSmall = AddImage_PrepareBitmap(pInfo, pInfo->hBitmapSmall);
  390. HBITMAP hMaskSmall = AddImage_PrepareBitmap(pInfo, pInfo->hMaskSmall);
  391. ImageList_Replace( m_himlSmall, iImageIndex, hBitmapSmall, hMaskSmall );
  392. AddImage_CleanupBitmap(pInfo, hBitmapSmall);
  393. AddImage_CleanupBitmap(pInfo, hMaskSmall);
  394. }
  395. else
  396. {
  397. ASSERT( pInfo->hIconSmall && pInfo->dwMask & ICIFLAG_ICON );
  398. HICON hIconSmall = AddImage_PrepareIcon(pInfo, pInfo->hIconSmall);
  399. ImageList_ReplaceIcon( m_himlSmall, iImageIndex, hIconSmall );
  400. AddImage_CleanupIcon(pInfo, hIconSmall);
  401. }
  402. }
  403. }
  404. else
  405. {
  406. iCacheIndex = DPA_AppendPtr( m_hListData, pNode );
  407. if ( iCacheIndex >= 0 )
  408. {
  409. if ( pInfo->dwMask & ICIFLAG_BITMAP )
  410. {
  411. if ( pInfo->dwMask & ICIFLAG_LARGE )
  412. {
  413. ASSERT( m_dwFlags & ICIIFLAG_LARGE );
  414. ASSERT( pInfo->hBitmapLarge );
  415. HBITMAP hBitmapLarge = AddImage_PrepareBitmap(pInfo, pInfo->hBitmapLarge);
  416. HBITMAP hMaskLarge = AddImage_PrepareBitmap(pInfo, pInfo->hMaskLarge);
  417. iImageIndex = ImageList_Add( m_himlLarge, hBitmapLarge, hMaskLarge);
  418. AddImage_CleanupBitmap(pInfo, hBitmapLarge);
  419. AddImage_CleanupBitmap(pInfo, hMaskLarge);
  420. }
  421. if ( pInfo->dwMask & ICIFLAG_SMALL )
  422. {
  423. ASSERT( m_dwFlags & ICIIFLAG_SMALL );
  424. ASSERT( pInfo->hBitmapSmall );
  425. HBITMAP hBitmapSmall = AddImage_PrepareBitmap(pInfo, pInfo->hBitmapSmall);
  426. HBITMAP hMaskSmall = AddImage_PrepareBitmap(pInfo, pInfo->hMaskSmall);
  427. iImageIndex = ImageList_Add( m_himlSmall, hBitmapSmall, hMaskSmall);
  428. AddImage_CleanupBitmap(pInfo, hBitmapSmall);
  429. AddImage_CleanupBitmap(pInfo, hMaskSmall);
  430. }
  431. }
  432. else
  433. {
  434. ASSERT( pInfo->dwMask & ICIFLAG_ICON );
  435. if ( pInfo->dwMask & ICIFLAG_LARGE )
  436. {
  437. ASSERT( m_dwFlags & ICIIFLAG_LARGE );
  438. ASSERT( pInfo->hIconLarge );
  439. HICON hIconLarge = AddImage_PrepareIcon(pInfo, pInfo->hIconLarge);
  440. iImageIndex = ImageList_AddIcon( m_himlLarge, hIconLarge );
  441. AddImage_CleanupIcon(pInfo, hIconLarge);
  442. }
  443. if ( pInfo->dwMask & ICIFLAG_SMALL )
  444. {
  445. ASSERT( m_dwFlags & ICIIFLAG_SMALL );
  446. ASSERT( pInfo->hIconSmall );
  447. HICON hIconSmall = AddImage_PrepareIcon(pInfo, pInfo->hIconSmall);
  448. iImageIndex = ImageList_AddIcon( m_himlSmall, hIconSmall );
  449. AddImage_CleanupIcon(pInfo, hIconSmall);
  450. }
  451. }
  452. ASSERT(iCacheIndex == iImageIndex);
  453. pNode->uImageIndex = iImageIndex;
  454. //TraceMsg(TF_CUSTOM2, "CImageListCache::AddImage -- Adding Image (CI:%d II:%d) ", iCacheIndex, iImageIndex);
  455. }
  456. else
  457. {
  458. // failed to add to the list...
  459. LocalFree( pNode );
  460. }
  461. }
  462. LeaveCriticalSection( &m_csLock );
  463. *puImageIndex = (UINT) iImageIndex;
  464. return (iImageIndex >= 0) ? S_OK : E_OUTOFMEMORY;
  465. }
  466. STDMETHODIMP CImageListCache::FindImage(LPCIMAGECACHEINFO pInfo, UINT *puImageIndex)
  467. {
  468. HRESULT hr = S_FALSE;
  469. ASSERT( m_hListData );
  470. DWORD dwMatch = pInfo->dwMask & (ICIFLAG_FLAGS | ICIFLAG_NAME | ICIFLAG_INDEX | ICIFLAG_DATESTAMP);
  471. DWORD dwMask;
  472. int iCacheIndex = 0;
  473. ICONCACHE_DATA * pNode = NULL;
  474. EnterCriticalSection( &m_csLock );
  475. do
  476. {
  477. dwMask = 0;
  478. pNode = (ICONCACHE_DATA *) DPA_GetPtr( m_hListData, iCacheIndex );
  479. if ( !pNode )
  480. {
  481. break;
  482. }
  483. if ((pNode->dwUsage & ICD_DELETED) || (pNode->iUsage == 0))
  484. {
  485. iCacheIndex ++;
  486. continue;
  487. }
  488. if (( dwMatch & ICIFLAG_NAME ) && StrCmpW( pInfo->pszName, pNode->szName ) == 0 )
  489. {
  490. // found it
  491. dwMask |= ICIFLAG_NAME;
  492. }
  493. if (( dwMatch& ICIFLAG_INDEX ) && pInfo->iIndex == pNode->iIndex )
  494. {
  495. dwMask |= ICIFLAG_INDEX;
  496. }
  497. if (( dwMatch & ICIFLAG_FLAGS ) && pInfo->dwFlags == pNode->dwFlags )
  498. {
  499. dwMask |= ICIFLAG_FLAGS;
  500. }
  501. if (( dwMatch & ICIFLAG_DATESTAMP ) &&
  502. ( pInfo->ftDateStamp.dwLowDateTime == pNode->ftDateStamp.dwLowDateTime &&
  503. pInfo->ftDateStamp.dwHighDateTime == pNode->ftDateStamp.dwHighDateTime ))
  504. {
  505. dwMask |= ICIFLAG_DATESTAMP;
  506. }
  507. iCacheIndex ++;
  508. }
  509. while ( dwMask != dwMatch);
  510. // found it, save the index... (as long as it was freed not deleted...
  511. if ( pNode && (dwMask == dwMatch) )
  512. {
  513. //TraceMsg(TF_CUSTOM2, "CImageListCache::FindImage *FOUND* (path=%s)", pNode->szName);
  514. hr = S_OK;
  515. *puImageIndex = (UINT) pNode->uImageIndex;
  516. // bump usage
  517. iCacheIndex --; // We had an extra increment at the end.
  518. if ( !(pNode->dwUsage & ICD_SYSTEM) )
  519. {
  520. if (m_dwFlags & ICIIFLAG_SORTBYUSED)
  521. {
  522. DPA_DeletePtr(m_hListData, iCacheIndex);
  523. iCacheIndex = DPA_AppendPtr(m_hListData, pNode);
  524. if (iCacheIndex == -1) // We failed to move the node...
  525. {
  526. LocalFree(pNode);
  527. *puImageIndex = (UINT) -1;
  528. hr = E_OUTOFMEMORY;
  529. }
  530. }
  531. else if ( !(pNode->dwUsage) && !(pInfo->dwMask & ICIFLAG_NOUSAGE ))
  532. {
  533. ASSERT(!(pNode->dwUsage & ICD_DELETED));
  534. pNode->iUsage++;
  535. }
  536. }
  537. }
  538. LeaveCriticalSection( &m_csLock );
  539. return hr;
  540. }
  541. STDMETHODIMP CImageListCache::Flush(BOOL fRelease)
  542. {
  543. ASSERT( m_hListData );
  544. EnterCriticalSection( &m_csLock );
  545. if ( fRelease )
  546. {
  547. // simply empty the data list. The ImageList never shrinks...
  548. DPA_EnumCallback( m_hListData, DestroyEnum, NULL );
  549. DPA_DeleteAllPtrs( m_hListData );
  550. if ( m_himlLarge )
  551. {
  552. ImageList_RemoveAll( m_himlLarge );
  553. }
  554. if ( m_himlSmall )
  555. {
  556. ImageList_RemoveAll( m_himlSmall );
  557. }
  558. }
  559. else
  560. {
  561. DPA_EnumCallback( m_hListData, UsageEnum, 0 );
  562. }
  563. LeaveCriticalSection( &m_csLock );
  564. return S_OK;
  565. }
  566. STDMETHODIMP CImageListCache::FreeImage(UINT uImageIndex)
  567. {
  568. ASSERT ( m_hListData );
  569. HRESULT hr = E_INVALIDARG;
  570. EnterCriticalSection(&m_csLock);
  571. ICONCACHE_DATA * pNode = GetNodeFromImageIndex(uImageIndex);
  572. if (pNode)
  573. {
  574. if (!pNode->dwUsage && pNode->iUsage)
  575. {
  576. hr = S_OK;
  577. if (m_dwFlags & ICIIFLAG_SORTBYUSED)
  578. {
  579. //TraceMsg(TF_CUSTOM2, "CImageListCache::FreeImage -- (CI::%d II::%d)", GetNodeIndexFromImageIndex(uImageIndex), uImageIndex);
  580. pNode->iUsage = 0;
  581. }
  582. else
  583. {
  584. pNode->iUsage--;
  585. }
  586. }
  587. else
  588. {
  589. hr = S_FALSE;
  590. }
  591. }
  592. LeaveCriticalSection(&m_csLock);
  593. return hr;
  594. }
  595. STDMETHODIMP CImageListCache::DeleteImage(UINT uImageIndex)
  596. {
  597. HRESULT hr = E_INVALIDARG;
  598. ASSERT ( m_hListData );
  599. EnterCriticalSection( &m_csLock );
  600. ICONCACHE_DATA * pNode = GetNodeFromImageIndex(uImageIndex);
  601. if (pNode)
  602. {
  603. if ( !pNode->dwUsage )
  604. {
  605. pNode->dwUsage = ICD_DELETED;
  606. hr = S_OK;
  607. }
  608. else
  609. {
  610. hr = S_FALSE;
  611. }
  612. }
  613. LeaveCriticalSection( &m_csLock );
  614. return hr;
  615. }
  616. STDMETHODIMP CImageListCache::ChangeImageInfo(UINT uImageIndex, LPCIMAGECACHEINFO pInfo)
  617. {
  618. ASSERT( m_hListData );
  619. EnterCriticalSection( &m_csLock );
  620. UINT uCacheIndex = GetNodeIndexFromImageIndex(uImageIndex);
  621. if (-1 == uCacheIndex)
  622. {
  623. LeaveCriticalSection( &m_csLock );
  624. return E_INVALIDARG;
  625. }
  626. ICONCACHE_DATA * pNode = CreateDataNode( pInfo );
  627. if (!pNode)
  628. {
  629. LeaveCriticalSection( &m_csLock );
  630. return E_OUTOFMEMORY;
  631. }
  632. ICONCACHE_DATA * pOld = (ICONCACHE_DATA *) DPA_GetPtr( m_hListData, uCacheIndex );
  633. ASSERT( pOld );
  634. DPA_SetPtr( m_hListData, uCacheIndex, pNode );
  635. pNode->iUsage = pOld->iUsage;
  636. pNode->dwUsage = pOld->dwUsage;
  637. pNode->uImageIndex = pOld->uImageIndex;
  638. LocalFree( pOld );
  639. if ( pInfo->dwMask & ( ICIFLAG_BITMAP | ICIFLAG_ICON ))
  640. {
  641. // update the picture....
  642. if ( pInfo->dwMask & ICIFLAG_LARGE )
  643. {
  644. if ( pInfo->dwMask & ICIFLAG_BITMAP )
  645. {
  646. ASSERT( pInfo->hBitmapLarge );
  647. ImageList_Replace( m_himlLarge, uImageIndex, pInfo->hBitmapLarge, pInfo->hMaskLarge );
  648. }
  649. else
  650. {
  651. ASSERT( pInfo->hIconLarge && pInfo->dwMask & ICIFLAG_ICON );
  652. ImageList_ReplaceIcon( m_himlLarge, uImageIndex, pInfo->hIconLarge );
  653. }
  654. }
  655. if ( pInfo->dwMask & ICIFLAG_SMALL )
  656. {
  657. if ( pInfo->dwMask & ICIFLAG_BITMAP )
  658. {
  659. ASSERT( pInfo->hBitmapSmall );
  660. ImageList_Replace( m_himlSmall, uImageIndex, pInfo->hBitmapSmall, pInfo->hMaskSmall );
  661. }
  662. else
  663. {
  664. ASSERT( pInfo->hIconSmall && pInfo->dwMask & ICIFLAG_ICON );
  665. ImageList_ReplaceIcon( m_himlLarge, uImageIndex, pInfo->hIconSmall );
  666. }
  667. }
  668. }
  669. LeaveCriticalSection(&m_csLock);
  670. return S_OK;
  671. }
  672. UINT CImageListCache::CountFreeSlots( )
  673. {
  674. ASSERT( m_hListData );
  675. int iSlot = 0;
  676. UINT uFree = 0;
  677. do
  678. {
  679. ICONCACHE_DATA * pNode = (ICONCACHE_DATA *) DPA_GetPtr( m_hListData, iSlot ++ );
  680. if ( !pNode )
  681. {
  682. break;
  683. }
  684. if (pNode->iUsage == 0 || (pNode->dwUsage & ICD_DELETED))
  685. {
  686. uFree++;
  687. }
  688. }
  689. while ( TRUE );
  690. return uFree;
  691. }
  692. STDMETHODIMP CImageListCache::GetCacheSize(UINT * puSize)
  693. {
  694. ASSERT( m_hListData );
  695. EnterCriticalSection( &m_csLock );
  696. *puSize = DPA_GetPtrCount( m_hListData ) - CountFreeSlots();
  697. LeaveCriticalSection( &m_csLock );
  698. return S_OK;
  699. }
  700. STDMETHODIMP CImageListCache::GetImageList(LPIMAGECACHEINITINFO pInfo )
  701. {
  702. ASSERT( pInfo->cbSize == sizeof( IMAGECACHEINITINFO ));
  703. if ( !(pInfo->dwMask & (ICIIFLAG_LARGE | ICIIFLAG_SMALL)))
  704. {
  705. // must specify one or both of large or small
  706. return E_INVALIDARG;
  707. }
  708. if ( m_hListData )
  709. {
  710. // we have already been created, just pass back the info if they match.....
  711. if ((( pInfo->dwMask & ICIIFLAG_SMALL ) && !m_himlSmall ) ||
  712. (( pInfo->dwMask & ICIIFLAG_LARGE ) && !m_himlLarge ) ||
  713. ( m_dwFlags != pInfo->dwMask ))
  714. {
  715. return E_INVALIDARG;
  716. }
  717. if ( pInfo->dwMask & ICIIFLAG_SMALL )
  718. {
  719. pInfo->himlSmall = m_himlSmall;
  720. }
  721. if ( pInfo->dwMask & ICIIFLAG_LARGE )
  722. {
  723. pInfo->himlLarge = m_himlLarge;
  724. }
  725. return S_FALSE;
  726. }
  727. m_hListData = DPA_Create( 30 );
  728. if ( !m_hListData )
  729. {
  730. return E_OUTOFMEMORY;
  731. }
  732. if ( pInfo->dwMask & ICIIFLAG_LARGE )
  733. {
  734. m_himlLarge = ImageList_Create( pInfo->rgSizeLarge.cx, pInfo->rgSizeLarge.cy, pInfo->dwFlags,
  735. pInfo->iStart, pInfo->iGrow );
  736. if ( !m_himlLarge )
  737. {
  738. return E_OUTOFMEMORY;
  739. }
  740. pInfo->himlLarge = m_himlLarge;
  741. }
  742. if ( pInfo->dwMask & ICIIFLAG_SMALL )
  743. {
  744. m_himlSmall = ImageList_Create( pInfo->rgSizeSmall.cx, pInfo->rgSizeSmall.cy, pInfo->dwFlags,
  745. pInfo->iStart, pInfo->iGrow );
  746. if ( !m_himlSmall )
  747. {
  748. return E_OUTOFMEMORY;
  749. }
  750. pInfo->himlSmall = m_himlSmall;
  751. }
  752. m_dwFlags = pInfo->dwMask;
  753. return S_OK;
  754. }
  755. int CImageListCache::FindEmptySlot()
  756. {
  757. // search for an element with a zero usage count...
  758. ASSERT( m_hListData );
  759. int iCacheIndex = 0;
  760. do
  761. {
  762. ICONCACHE_DATA * pNode = (ICONCACHE_DATA *) DPA_GetPtr( m_hListData, iCacheIndex );
  763. if ( !pNode )
  764. {
  765. break;
  766. }
  767. if (pNode->iUsage == 0 || (pNode->dwUsage & ICD_DELETED))
  768. {
  769. return iCacheIndex;
  770. }
  771. iCacheIndex ++;
  772. } while (TRUE);
  773. return -1;
  774. }
  775. STDMETHODIMP CImageListCache::GetUsage(UINT uImageIndex, UINT * puUsage)
  776. {
  777. ASSERT( m_hListData );
  778. EnterCriticalSection( &m_csLock );
  779. HRESULT hr = E_INVALIDARG;
  780. ICONCACHE_DATA * pNode = GetNodeFromImageIndex(uImageIndex);
  781. if (pNode)
  782. {
  783. if (pNode->dwUsage & ICD_DELETED)
  784. {
  785. *puUsage = ICD_USAGE_DELETED;
  786. }
  787. else if (pNode->dwUsage & ICD_SYSTEM)
  788. {
  789. *puUsage = ICD_USAGE_SYSTEM;
  790. }
  791. else if (pNode->dwUsage & ICD_NOUSAGE)
  792. {
  793. *puUsage = ICD_USAGE_NOUSAGE;
  794. }
  795. else
  796. {
  797. *puUsage = pNode->iUsage;
  798. }
  799. hr = S_OK;
  800. }
  801. LeaveCriticalSection( &m_csLock );
  802. return hr;
  803. }
  804. STDMETHODIMP CImageListCache::GetImageInfo(UINT uImageIndex, LPIMAGECACHEINFO pInfo)
  805. {
  806. HRESULT hr;
  807. ASSERT( m_hListData );
  808. EnterCriticalSection( &m_csLock );
  809. ICONCACHE_DATA * pNode = GetNodeFromImageIndex(uImageIndex);
  810. if (pNode)
  811. {
  812. hr = E_NOTIMPL;
  813. if ( pInfo->dwMask & ICIFLAG_DATESTAMP )
  814. {
  815. if ( pNode->dwFlags & ICIFLAG_DATESTAMP )
  816. {
  817. pInfo->ftDateStamp = pNode->ftDateStamp;
  818. hr = S_OK;
  819. }
  820. else
  821. {
  822. hr = E_FAIL;
  823. }
  824. }
  825. if ( pInfo->dwMask & ICIFLAG_NOUSAGE )
  826. {
  827. hr = S_OK;
  828. }
  829. pInfo->dwMask = pNode->dwFlags & pInfo->dwMask;
  830. }
  831. else
  832. hr = E_INVALIDARG;
  833. LeaveCriticalSection(&m_csLock);
  834. return hr;
  835. }
  836. STDMETHODIMP CImageListCache::GetImageIndexFromCacheIndex( UINT iCacheIndex, UINT * puImageIndex )
  837. {
  838. ASSERT( m_hListData );
  839. HRESULT hr = E_INVALIDARG;
  840. EnterCriticalSection( &m_csLock );
  841. ICONCACHE_DATA *pNode = (ICONCACHE_DATA *) DPA_GetPtr( m_hListData, iCacheIndex );
  842. *puImageIndex = (UINT) -1;
  843. if (pNode)
  844. {
  845. *puImageIndex = (UINT) pNode->uImageIndex;
  846. hr = S_OK;
  847. }
  848. LeaveCriticalSection(&m_csLock);
  849. return hr;
  850. }
  851. ICONCACHE_DATA * CImageListCache::GetNodeFromImageIndex( UINT iImageIndex )
  852. {
  853. UINT iCacheIndex = GetNodeIndexFromImageIndex(iImageIndex);
  854. return (iCacheIndex == -1) ? NULL : (ICONCACHE_DATA *) DPA_GetPtr( m_hListData, iCacheIndex );
  855. }
  856. UINT CImageListCache::GetNodeIndexFromImageIndex( UINT iImageIndex )
  857. {
  858. UINT iCacheIndex = 0;
  859. ICONCACHE_DATA * pNode = NULL;
  860. // We must assume that we have the critical section here or else the data would be
  861. // meaningless upon return from this function.
  862. do
  863. {
  864. pNode = (ICONCACHE_DATA *) DPA_GetPtr( m_hListData, iCacheIndex );
  865. if ( !pNode )
  866. {
  867. break;
  868. }
  869. if (pNode->dwUsage & ICD_DELETED)
  870. {
  871. iCacheIndex ++;
  872. continue;
  873. }
  874. iCacheIndex ++;
  875. }
  876. while ( pNode->uImageIndex != iImageIndex );
  877. return (pNode ? iCacheIndex - 1 : -1);
  878. }