Leaked source code of windows server 2003
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.

1070 lines
29 KiB

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