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.

5261 lines
143 KiB

  1. #include "ctlspriv.h"
  2. #include "image.h"
  3. #include "math.h"
  4. #ifndef AC_MIRRORBITMAP
  5. #define AC_MIRRORBITMAP 0 // BUGBUG: Remove me
  6. #endif
  7. void ImageList_DeleteDragBitmaps();
  8. BOOL ImageList_SetDragImage(HIMAGELIST piml, int i, int dxHotspot, int dyHotspot);
  9. HDC g_hdcSrc = NULL;
  10. HBITMAP g_hbmSrc = NULL;
  11. HBITMAP g_hbmDcDeselect = NULL;
  12. HDC g_hdcDst = NULL;
  13. HBITMAP g_hbmDst = NULL;
  14. int g_iILRefCount = 0;
  15. HRESULT WINAPI HIMAGELIST_QueryInterface(HIMAGELIST himl, REFIID riid, void** ppv)
  16. {
  17. *ppv = NULL;
  18. if (himl)
  19. {
  20. // First Convert the HIMAGELIST to an IUnknown.
  21. IUnknown* punk = reinterpret_cast<IUnknown*>(himl);
  22. // Now, we need to validate the object. CImageListBase contains the goo needed to figure out if this
  23. // is a valid imagelist.
  24. CImageListBase* pval = FindImageListBase(punk);
  25. // Now we call some private member.
  26. if (pval->IsValid())
  27. {
  28. // If it's valid then we can QI safely.
  29. return punk->QueryInterface(riid, ppv);
  30. }
  31. }
  32. return E_POINTER;
  33. }
  34. HRESULT WimpyDrawEx(IImageList* pux, int i, HDC hdcDst, int x, int y, int cx, int cy, COLORREF rgbBk, COLORREF rgbFg, UINT fStyle)
  35. {
  36. IMAGELISTDRAWPARAMS imldp = {0};
  37. imldp.cbSize = sizeof(imldp);
  38. imldp.himl = reinterpret_cast<HIMAGELIST>(pux);
  39. imldp.i = i;
  40. imldp.hdcDst = hdcDst;
  41. imldp.x = x;
  42. imldp.y = y;
  43. imldp.cx = cx;
  44. imldp.cy = cy;
  45. imldp.rgbBk = rgbBk;
  46. imldp.rgbFg = rgbFg;
  47. imldp.fStyle = fStyle;
  48. imldp.dwRop = SRCCOPY;
  49. return pux->Draw(&imldp);
  50. }
  51. HRESULT WimpyDraw(IImageList* pux, int i, HDC hdcDst, int x, int y, UINT fStyle)
  52. {
  53. IMAGELISTDRAWPARAMS imldp = {0};
  54. imldp.cbSize = sizeof(imldp);
  55. imldp.himl = reinterpret_cast<HIMAGELIST>(pux);
  56. imldp.i = i;
  57. imldp.hdcDst = hdcDst;
  58. imldp.x = x;
  59. imldp.y = y;
  60. imldp.rgbBk = CLR_DEFAULT;
  61. imldp.rgbFg = CLR_DEFAULT;
  62. imldp.fStyle = fStyle;
  63. imldp.dwRop = SRCCOPY;
  64. return pux->Draw(&imldp);
  65. }
  66. CImageList::CImageList() : _cRef(1)
  67. {
  68. }
  69. CImageList::~CImageList()
  70. {
  71. if (_pimlMirror)
  72. {
  73. _pimlMirror->Release();
  74. }
  75. _Destroy();
  76. }
  77. DWORD CImageList::_GetItemFlags(int i)
  78. {
  79. DWORD dw = 0;
  80. // NOTE: Currently we only add the flags in 32bit mode. If needed, you have
  81. // to modify ::Load in order to add items during a load. I'm just lazy
  82. if ((_flags & ILC_COLORMASK) == ILC_COLOR32)
  83. DSA_GetItem(_dsaFlags, i, &dw);
  84. return dw;
  85. }
  86. void CImageList::SetItemFlags(int i, DWORD dwFlags)
  87. {
  88. if (_dsaFlags)
  89. DSA_SetItem(_dsaFlags, i, &dwFlags);
  90. }
  91. HRESULT CImageList::Initialize(int cxI, int cyI, UINT flagsI, int cInitialI, int cGrowI)
  92. {
  93. HRESULT hr = E_OUTOFMEMORY;
  94. if (cGrowI < 4)
  95. {
  96. cGrowI = 4;
  97. }
  98. else
  99. {
  100. // round up by 4's
  101. cGrowI = (cGrowI + 3) & ~3;
  102. }
  103. _cStrip = 1;
  104. _cGrow = cGrowI;
  105. _cx = cxI;
  106. _cy = cyI;
  107. _clrBlend = CLR_NONE;
  108. _clrBk = CLR_NONE;
  109. _hbrBk = (HBRUSH)GetStockObject(BLACK_BRUSH);
  110. _fSolidBk = TRUE;
  111. _flags = flagsI;
  112. _pimlMirror = NULL;
  113. //
  114. // Initialize the overlay indexes to -1 since 0 is a valid index.
  115. //
  116. for (int i = 0; i < NUM_OVERLAY_IMAGES; i++)
  117. {
  118. _aOverlayIndexes[i] = -1;
  119. }
  120. _hdcImage = CreateCompatibleDC(NULL);
  121. if (_hdcImage)
  122. {
  123. hr = S_OK;
  124. if (_flags & ILC_MASK)
  125. {
  126. _hdcMask = CreateCompatibleDC(NULL);
  127. if (!_hdcMask)
  128. hr = E_OUTOFMEMORY;
  129. }
  130. if (SUCCEEDED(hr))
  131. {
  132. hr = _ReAllocBitmaps(cInitialI + 1);
  133. if (FAILED(hr))
  134. {
  135. hr = _ReAllocBitmaps(2);
  136. }
  137. }
  138. }
  139. // Don't do this if we are already initialized, we just want to pass new information....
  140. if (!_fInitialized)
  141. g_iILRefCount++;
  142. _fInitialized = TRUE;
  143. return hr;
  144. }
  145. HRESULT CImageList::QueryInterface(REFIID riid, void **ppv)
  146. {
  147. static const QITAB qit[] =
  148. {
  149. QITABENT(CImageList, IImageListPriv),
  150. QITABENT(CImageList, IImageList),
  151. QITABENT(CImageList, IImageListPersistStream),
  152. QITABENT(CImageList, IPersistStream),
  153. QITABENTMULTI(CImageList, IPersist, IPersistStream),
  154. { 0 },
  155. };
  156. return QISearch(this, (LPCQITAB)qit, riid, ppv);
  157. }
  158. ULONG CImageList::AddRef()
  159. {
  160. return InterlockedIncrement(&_cRef);
  161. }
  162. ULONG CImageList::Release()
  163. {
  164. ASSERT( 0 != _cRef );
  165. ULONG cRef = InterlockedDecrement(&_cRef);
  166. if ( 0 == cRef )
  167. {
  168. delete this;
  169. }
  170. return cRef;
  171. }
  172. HRESULT CImageList::GetPrivateGoo(HBITMAP* phbmp, HDC* phdc, HBITMAP* phbmpMask, HDC* phdcMask)
  173. {
  174. if (phbmp)
  175. *phbmp = _hbmImage;
  176. if (phdc)
  177. *phdc = _hdcImage;
  178. if (phbmpMask)
  179. *phbmpMask = _hbmMask;
  180. if (phdcMask)
  181. *phdcMask = _hdcMask;
  182. return S_OK;
  183. }
  184. HRESULT CImageList::GetMirror(REFIID riid, void** ppv)
  185. {
  186. if (_pimlMirror)
  187. return _pimlMirror->QueryInterface(riid, ppv);
  188. return E_NOINTERFACE;
  189. }
  190. //
  191. // global work buffer, this buffer is always a DDB never a DIBSection
  192. //
  193. HBITMAP g_hbmWork = NULL; // work buffer.
  194. BITMAP g_bmWork = {0}; // work buffer size
  195. HBRUSH g_hbrMonoDither = NULL; // gray dither brush for dragging
  196. HBRUSH g_hbrStripe = NULL;
  197. #define NOTSRCAND 0x00220326L
  198. #define ROP_PSo 0x00FC008A
  199. #define ROP_DPo 0x00FA0089
  200. #define ROP_DPna 0x000A0329
  201. #define ROP_DPSona 0x00020c89
  202. #define ROP_SDPSanax 0x00E61ce8
  203. #define ROP_DSna 0x00220326
  204. #define ROP_PSDPxax 0x00b8074a
  205. #define ROP_PatNotMask 0x00b8074a // D <- S==0 ? P : D
  206. #define ROP_PatMask 0x00E20746 // D <- S==1 ? P : D
  207. #define ROP_MaskPat 0x00AC0744 // D <- P==1 ? D : S
  208. #define ROP_DSo 0x00EE0086L
  209. #define ROP_DSno 0x00BB0226L
  210. #define ROP_DSa 0x008800C6L
  211. static int g_iDither = 0;
  212. void InitDitherBrush()
  213. {
  214. HBITMAP hbmTemp;
  215. static const WORD graybits[] = {0xAAAA, 0x5555, 0xAAAA, 0x5555,
  216. 0xAAAA, 0x5555, 0xAAAA, 0x5555};
  217. if (g_iDither)
  218. {
  219. g_iDither++;
  220. }
  221. else
  222. {
  223. // build the dither brush. this is a fixed 8x8 bitmap
  224. hbmTemp = CreateBitmap(8, 8, 1, 1, graybits);
  225. if (hbmTemp)
  226. {
  227. // now use the bitmap for what it was really intended...
  228. g_hbrMonoDither = CreatePatternBrush(hbmTemp);
  229. DeleteObject(hbmTemp);
  230. g_iDither++;
  231. }
  232. }
  233. }
  234. void TerminateDitherBrush()
  235. {
  236. g_iDither--;
  237. if (g_iDither == 0)
  238. {
  239. DeleteObject(g_hbrMonoDither);
  240. g_hbrMonoDither = NULL;
  241. }
  242. }
  243. /*
  244. ** GetScreenDepth()
  245. */
  246. int GetScreenDepth()
  247. {
  248. int i;
  249. HDC hdc = GetDC(NULL);
  250. i = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES);
  251. ReleaseDC(NULL, hdc);
  252. return i;
  253. }
  254. //
  255. // should we use a DIB section on the current device?
  256. //
  257. // the main goal of using DS is to save memory, but they draw slow
  258. // on some devices.
  259. //
  260. // 4bpp Device (ie 16 color VGA) dont use DS
  261. // 8bpp Device (ie 256 color SVGA) use DS if DIBENG based.
  262. // >8bpp Device (ie 16bpp 24bpp) always use DS, saves memory
  263. //
  264. #define CAPS1 94 /* other caps */
  265. #define C1_DIBENGINE 0x0010 /* DIB Engine compliant driver */
  266. //
  267. // create a bitmap compatible with the given ImageList
  268. //
  269. HBITMAP CImageList::_CreateBitmap(int cx, int cy, RGBQUAD** ppargb)
  270. {
  271. HDC hdc;
  272. HBITMAP hbm;
  273. struct
  274. {
  275. BITMAPINFOHEADER bi;
  276. DWORD ct[256];
  277. } dib;
  278. hdc = GetDC(NULL);
  279. // no color depth was specifed
  280. //
  281. // if we are on a DIBENG based DISPLAY, we use 4bit DIBSections to save
  282. // memory.
  283. //
  284. if ((_flags & ILC_COLORMASK) == 0)
  285. {
  286. _flags |= ILC_COLOR4;
  287. }
  288. if ((_flags & ILC_COLORMASK) != ILC_COLORDDB)
  289. {
  290. dib.bi.biSize = sizeof(BITMAPINFOHEADER);
  291. dib.bi.biWidth = cx;
  292. dib.bi.biHeight = cy;
  293. dib.bi.biPlanes = 1;
  294. dib.bi.biBitCount = (_flags & ILC_COLORMASK);
  295. dib.bi.biCompression = BI_RGB;
  296. dib.bi.biSizeImage = 0;
  297. dib.bi.biXPelsPerMeter = 0;
  298. dib.bi.biYPelsPerMeter = 0;
  299. dib.bi.biClrUsed = 16;
  300. dib.bi.biClrImportant = 0;
  301. dib.ct[0] = 0x00000000; // 0000 black
  302. dib.ct[1] = 0x00800000; // 0001 dark red
  303. dib.ct[2] = 0x00008000; // 0010 dark green
  304. dib.ct[3] = 0x00808000; // 0011 mustard
  305. dib.ct[4] = 0x00000080; // 0100 dark blue
  306. dib.ct[5] = 0x00800080; // 0101 purple
  307. dib.ct[6] = 0x00008080; // 0110 dark turquoise
  308. dib.ct[7] = 0x00C0C0C0; // 1000 gray
  309. dib.ct[8] = 0x00808080; // 0111 dark gray
  310. dib.ct[9] = 0x00FF0000; // 1001 red
  311. dib.ct[10] = 0x0000FF00; // 1010 green
  312. dib.ct[11] = 0x00FFFF00; // 1011 yellow
  313. dib.ct[12] = 0x000000FF; // 1100 blue
  314. dib.ct[13] = 0x00FF00FF; // 1101 pink (magenta)
  315. dib.ct[14] = 0x0000FFFF; // 1110 cyan
  316. dib.ct[15] = 0x00FFFFFF; // 1111 white
  317. if (dib.bi.biBitCount == 8)
  318. {
  319. HPALETTE hpal;
  320. int i;
  321. if (hpal = CreateHalftonePalette(NULL))
  322. {
  323. i = GetPaletteEntries(hpal, 0, 256, (LPPALETTEENTRY)&dib.ct[0]);
  324. DeleteObject(hpal);
  325. if (i > 64)
  326. {
  327. dib.bi.biClrUsed = i;
  328. for (i=0; i<(int)dib.bi.biClrUsed; i++)
  329. dib.ct[i] = RGB(GetBValue(dib.ct[i]),GetGValue(dib.ct[i]),GetRValue(dib.ct[i]));
  330. }
  331. }
  332. else
  333. {
  334. dib.bi.biBitCount = (_flags & ILC_COLORMASK);
  335. dib.bi.biClrUsed = 256;
  336. }
  337. if (dib.bi.biClrUsed <= 16)
  338. dib.bi.biBitCount = 4;
  339. }
  340. hbm = CreateDIBSection(hdc, (LPBITMAPINFO)&dib, DIB_RGB_COLORS, (PVOID*)ppargb, NULL, 0);
  341. }
  342. else
  343. {
  344. hbm = CreateCompatibleBitmap(hdc, cx, cy);
  345. }
  346. ReleaseDC(NULL, hdc);
  347. return hbm;
  348. }
  349. EXTERN_C HBITMAP CreateColorBitmap(int cx, int cy)
  350. {
  351. HBITMAP hbm;
  352. HDC hdc;
  353. hdc = GetDC(NULL);
  354. //
  355. // on a multimonitor system with mixed bitdepths
  356. // always use a 32bit bitmap for our work buffer
  357. // this will prevent us from losing colors when
  358. // blting to and from the screen. this is mainly
  359. // important for the drag & drop offscreen buffers.
  360. //
  361. if (!(GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) &&
  362. GetSystemMetrics(SM_CMONITORS) > 1 &&
  363. GetSystemMetrics(SM_SAMEDISPLAYFORMAT) == 0)
  364. {
  365. void* p;
  366. BITMAPINFO bi = {sizeof(BITMAPINFOHEADER), cx, cy, 1, 32};
  367. hbm = CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, &p, NULL, 0);
  368. }
  369. else
  370. {
  371. hbm = CreateCompatibleBitmap(hdc, cx, cy);
  372. }
  373. ReleaseDC(NULL, hdc);
  374. return hbm;
  375. }
  376. HBITMAP CreateDIB(HDC h, int cx, int cy, RGBQUAD** pprgb)
  377. {
  378. BITMAPINFO bi = {0};
  379. bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
  380. bi.bmiHeader.biWidth = cx;
  381. bi.bmiHeader.biHeight = cy;
  382. bi.bmiHeader.biPlanes = 1;
  383. bi.bmiHeader.biBitCount = 32;
  384. bi.bmiHeader.biCompression = BI_RGB;
  385. return CreateDIBSection(h, &bi, DIB_RGB_COLORS, (void**)pprgb, NULL, 0);
  386. }
  387. BOOL DIBHasAlpha(int cx, int cy, RGBQUAD* prgb)
  388. {
  389. int cTotal = cx * cy;
  390. for (int i = 0; i < cTotal; i++)
  391. {
  392. if (prgb[i].rgbReserved != 0)
  393. return TRUE;
  394. }
  395. return FALSE;
  396. }
  397. void PreProcessDIB(int cx, int cy, RGBQUAD* pargb)
  398. {
  399. int cTotal = cx * cy;
  400. for (int i = 0; i < cTotal; i++)
  401. {
  402. RGBQUAD* prgb = &pargb[i];
  403. if (prgb->rgbReserved != 0)
  404. {
  405. prgb->rgbRed = ((prgb->rgbRed * prgb->rgbReserved) + 128) / 255;
  406. prgb->rgbGreen = ((prgb->rgbGreen * prgb->rgbReserved) + 128) / 255;
  407. prgb->rgbBlue = ((prgb->rgbBlue * prgb->rgbReserved) + 128) / 255;
  408. }
  409. else
  410. {
  411. *((DWORD*)prgb) = 0;
  412. }
  413. }
  414. }
  415. EXTERN_C HBITMAP CreateMonoBitmap(int cx, int cy)
  416. {
  417. #ifdef MONO_DIB
  418. struct
  419. {
  420. BITMAPINFOHEADER bi;
  421. DWORD ct[2];
  422. } dib = {0};
  423. dib.bi.biSize = sizeof(dib.bi);
  424. dib.bi.biWidth = cx;
  425. dib.bi.biHeight = cy;
  426. dib.bi.biPlanes = 1;
  427. dib.bi.biBitCount = 1;
  428. dib.bi.biCompression = BI_RGB;
  429. dib.ct[0] = 0x00000000;
  430. dib.ct[1] = 0x00ffffff;
  431. HBITMAP hbmp = NULL;
  432. HDC hdc = CreateCompatibleDC(NULL);
  433. if (hdc)
  434. {
  435. hbmp = CreateDIBSection(hdc, (BITMAPINFO*)&dib, DIB_PAL_COLORS, NULL, NULL, 0);
  436. DeleteDC(hdc);
  437. }
  438. return hbmp;
  439. #else
  440. return CreateBitmap(cx, cy, 1, 1, NULL);
  441. #endif
  442. }
  443. //============================================================================
  444. BOOL CImageList::GlobalInit(void)
  445. {
  446. HDC hdcScreen;
  447. static const WORD stripebits[] = {0x7777, 0xdddd, 0x7777, 0xdddd,
  448. 0x7777, 0xdddd, 0x7777, 0xdddd};
  449. HBITMAP hbmTemp;
  450. TraceMsg(TF_IMAGELIST, "CImageList::GlobalInit");
  451. // if already initialized, there is nothing to do
  452. if (g_hdcDst)
  453. return TRUE;
  454. hdcScreen = GetDC(HWND_DESKTOP);
  455. g_hdcSrc = CreateCompatibleDC(hdcScreen);
  456. g_hdcDst = CreateCompatibleDC(hdcScreen);
  457. InitDitherBrush();
  458. hbmTemp = CreateBitmap(8, 8, 1, 1, stripebits);
  459. if (hbmTemp)
  460. {
  461. // initialize the deselect 1x1 bitmap
  462. g_hbmDcDeselect = SelectBitmap(g_hdcDst, hbmTemp);
  463. SelectBitmap(g_hdcDst, g_hbmDcDeselect);
  464. g_hbrStripe = CreatePatternBrush(hbmTemp);
  465. DeleteObject(hbmTemp);
  466. }
  467. ReleaseDC(HWND_DESKTOP, hdcScreen);
  468. if (!g_hdcSrc || !g_hdcDst || !g_hbrMonoDither)
  469. {
  470. CImageList::GlobalUninit();
  471. TraceMsg(TF_ERROR, "ImageList: Unable to initialize");
  472. return FALSE;
  473. }
  474. return TRUE;
  475. }
  476. void CImageList::GlobalUninit()
  477. {
  478. TerminateDitherBrush();
  479. if (g_hbrStripe)
  480. {
  481. DeleteObject(g_hbrStripe);
  482. g_hbrStripe = NULL;
  483. }
  484. ImageList_DeleteDragBitmaps();
  485. if (g_hdcDst)
  486. {
  487. CImageList::SelectDstBitmap(NULL);
  488. DeleteDC(g_hdcDst);
  489. g_hdcDst = NULL;
  490. }
  491. if (g_hdcSrc)
  492. {
  493. CImageList::SelectSrcBitmap(NULL);
  494. DeleteDC(g_hdcSrc);
  495. g_hdcSrc = NULL;
  496. }
  497. if (g_hbmWork)
  498. {
  499. DeleteBitmap(g_hbmWork);
  500. g_hbmWork = NULL;
  501. }
  502. }
  503. void CImageList::SelectDstBitmap(HBITMAP hbmDst)
  504. {
  505. ASSERTCRITICAL;
  506. if (hbmDst != g_hbmDst)
  507. {
  508. // If it's selected in the source DC, then deselect it first
  509. //
  510. if (hbmDst && hbmDst == g_hbmSrc)
  511. CImageList::SelectSrcBitmap(NULL);
  512. SelectBitmap(g_hdcDst, hbmDst ? hbmDst : g_hbmDcDeselect);
  513. g_hbmDst = hbmDst;
  514. }
  515. }
  516. void CImageList::SelectSrcBitmap(HBITMAP hbmSrc)
  517. {
  518. ASSERTCRITICAL;
  519. if (hbmSrc != g_hbmSrc)
  520. {
  521. // If it's selected in the dest DC, then deselect it first
  522. //
  523. if (hbmSrc && hbmSrc == g_hbmDst)
  524. CImageList::SelectDstBitmap(NULL);
  525. SelectBitmap(g_hdcSrc, hbmSrc ? hbmSrc : g_hbmDcDeselect);
  526. g_hbmSrc = hbmSrc;
  527. }
  528. }
  529. HDC ImageList_GetWorkDC(HDC hdc, BOOL f32bpp, int dx, int dy)
  530. {
  531. ASSERTCRITICAL;
  532. int iDepth = GetDeviceCaps(hdc, BITSPIXEL);
  533. if (g_hbmWork == NULL ||
  534. iDepth != g_bmWork.bmBitsPixel ||
  535. g_bmWork.bmWidth != dx ||
  536. g_bmWork.bmHeight != dy ||
  537. (f32bpp && iDepth != 32))
  538. {
  539. CImageList::_DeleteBitmap(g_hbmWork);
  540. g_hbmWork = NULL;
  541. if (dx == 0 || dy == 0)
  542. return NULL;
  543. if (f32bpp)
  544. g_hbmWork = CreateDIB(hdc, dx, dy, NULL);
  545. else
  546. g_hbmWork = CreateCompatibleBitmap(hdc, dx, dy);
  547. if (g_hbmWork)
  548. {
  549. GetObject(g_hbmWork, sizeof(g_bmWork), &g_bmWork);
  550. }
  551. }
  552. CImageList::SelectSrcBitmap(g_hbmWork);
  553. if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
  554. {
  555. HPALETTE hpal = (HPALETTE)SelectPalette(hdc, (HPALETTE)GetStockObject(DEFAULT_PALETTE), TRUE);
  556. SelectPalette(g_hdcSrc, hpal, TRUE);
  557. }
  558. return g_hdcSrc;
  559. }
  560. void ImageList_ReleaseWorkDC(HDC hdc)
  561. {
  562. ASSERTCRITICAL;
  563. ASSERT(hdc == g_hdcSrc);
  564. if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
  565. {
  566. SelectPalette(hdc, (HPALETTE)GetStockObject(DEFAULT_PALETTE), TRUE);
  567. }
  568. }
  569. void CImageList::_DeleteBitmap(HBITMAP hbm)
  570. {
  571. ASSERTCRITICAL;
  572. if (hbm)
  573. {
  574. if (g_hbmDst == hbm)
  575. CImageList::SelectDstBitmap(NULL);
  576. if (g_hbmSrc == hbm)
  577. CImageList::SelectSrcBitmap(NULL);
  578. DeleteBitmap(hbm);
  579. }
  580. }
  581. #define ILC_WIN95 (ILC_MASK | ILC_COLORMASK | ILC_SHARED | ILC_PALETTE)
  582. //============================================================================
  583. HRESULT CImageList::InitGlobals()
  584. {
  585. HRESULT hr = S_OK;
  586. ENTERCRITICAL;
  587. if (!g_iILRefCount)
  588. {
  589. if (!CImageList::GlobalInit())
  590. {
  591. hr = E_OUTOFMEMORY;
  592. }
  593. }
  594. LEAVECRITICAL;
  595. return S_OK;
  596. }
  597. CImageList* CImageList::Create(int cx, int cy, UINT flags, int cInitial, int cGrow)
  598. {
  599. CImageList* piml = NULL;
  600. HRESULT hr = S_OK;
  601. if (cx < 0 || cy < 0)
  602. return NULL;
  603. // Validate the flags
  604. if (flags & ~ILC_VALID)
  605. return NULL;
  606. hr = InitGlobals();
  607. ENTERCRITICAL;
  608. if (SUCCEEDED(hr))
  609. {
  610. piml = new CImageList();
  611. // allocate the bitmap PLUS one re-usable entry
  612. if (piml)
  613. {
  614. hr = piml->Initialize(cx, cy, flags, cInitial, cGrow);
  615. if (FAILED(hr))
  616. {
  617. piml->Release();
  618. piml = NULL;
  619. }
  620. }
  621. }
  622. LEAVECRITICAL;
  623. return piml;
  624. }
  625. void CImageList::_Destroy()
  626. {
  627. ENTERCRITICAL;
  628. // nuke dc's
  629. if (_hdcImage)
  630. {
  631. SelectObject(_hdcImage, g_hbmDcDeselect);
  632. DeleteDC(_hdcImage);
  633. }
  634. if (_hdcMask)
  635. {
  636. SelectObject(_hdcMask, g_hbmDcDeselect);
  637. DeleteDC(_hdcMask);
  638. }
  639. // nuke bitmaps
  640. if (_hbmImage)
  641. _DeleteBitmap(_hbmImage);
  642. if (_hbmMask)
  643. _DeleteBitmap(_hbmMask);
  644. if (_hbrBk)
  645. DeleteObject(_hbrBk);
  646. //Clean up DSA
  647. if (_dsaFlags)
  648. DSA_Destroy(_dsaFlags);
  649. if (_fInitialized)
  650. {
  651. // one less use of imagelists. if it's the last, terminate the imagelist
  652. g_iILRefCount--;
  653. if (!g_iILRefCount)
  654. CImageList::GlobalUninit();
  655. }
  656. LEAVECRITICAL;
  657. }
  658. HRESULT CImageList::GetImageCount(int* pi)
  659. {
  660. *pi = _cImage;
  661. return S_OK;
  662. }
  663. HRESULT CImageList::SetImageCount(UINT uAlloc)
  664. {
  665. ENTERCRITICAL;
  666. HRESULT hr = _ReAllocBitmaps(-((int)uAlloc + 2)); // Two because we need a spare image
  667. if (SUCCEEDED(hr))
  668. {
  669. _cImage = (int)uAlloc;
  670. }
  671. LEAVECRITICAL;
  672. return hr;
  673. }
  674. HRESULT CImageList::GetIconSize(int* pcx, int* pcy)
  675. {
  676. if (!pcx || !pcy)
  677. return E_INVALIDARG;
  678. *pcx = _cx;
  679. *pcy = _cy;
  680. return S_OK;
  681. }
  682. //
  683. // change the size of a existing image list
  684. // also removes all items
  685. //
  686. HRESULT CImageList::_SetIconSize(int cxImage, int cyImage)
  687. {
  688. if (_cx == cxImage && _cy == cyImage)
  689. return S_FALSE; // no change
  690. if (_cx < 0 || _cy < 0)
  691. return E_INVALIDARG; // invalid dimensions
  692. _cx = cxImage;
  693. _cy = cyImage;
  694. return Remove(-1);
  695. }
  696. HRESULT CImageList::SetIconSize(int cxImage, int cyImage)
  697. {
  698. if (_pimlMirror)
  699. {
  700. _pimlMirror->_SetIconSize(cxImage, cyImage);
  701. }
  702. return _SetIconSize(cxImage, cyImage);
  703. }
  704. //
  705. // ImageList_SetFlags
  706. //
  707. // change the image list flags, then rebuilds the bitmaps.
  708. //
  709. // the only reason to call this function is to change the
  710. // color depth of the image list, the shell needs to do this
  711. // when the screen depth changes and it wants to use HiColor icons.
  712. //
  713. HRESULT CImageList::SetFlags(UINT uFlags)
  714. {
  715. HBITMAP hOldImage;
  716. // check for valid input flags
  717. if (uFlags & ~ILC_VALID)
  718. return E_INVALIDARG;
  719. // you cant change these flags.
  720. if ((uFlags ^ _flags) & ILC_SHARED)
  721. return E_INVALIDARG;
  722. if (_pimlMirror)
  723. _pimlMirror->SetFlags(uFlags);
  724. // now change the flags and rebuild the bitmaps.
  725. _flags = uFlags;
  726. // set the old bitmap to NULL, so when Imagelist_remove calls
  727. // ImageList_createBitmap, it will not call CreatecomptibleBitmap,
  728. // it will create the spec for the bitmap from scratch..
  729. hOldImage = _hbmImage;
  730. _hbmImage = NULL;
  731. Remove(-1);
  732. // imagelist::remove will have ensured that the old image is no longer selected
  733. // thus we can now delete it...
  734. if ( hOldImage )
  735. DeleteObject( hOldImage );
  736. return S_OK;
  737. }
  738. HRESULT CImageList::GetFlags(UINT* puFlags)
  739. {
  740. *puFlags = (_flags & ILC_VALID) | (_pimlMirror ? ILC_MIRROR : 0);
  741. return S_OK;
  742. }
  743. // reset the background color of images iFirst through iLast
  744. void CImageList::_ResetBkColor(int iFirst, int iLast, COLORREF clr)
  745. {
  746. HBRUSH hbrT=NULL;
  747. DWORD rop;
  748. if (_hdcMask == NULL)
  749. return;
  750. if (clr == CLR_BLACK || clr == CLR_NONE)
  751. {
  752. rop = ROP_DSna;
  753. }
  754. else if (clr == CLR_WHITE)
  755. {
  756. rop = ROP_DSo;
  757. }
  758. else
  759. {
  760. ASSERT(_hbrBk);
  761. ASSERT(_clrBk == clr);
  762. rop = ROP_PatMask;
  763. hbrT = SelectBrush(_hdcImage, _hbrBk);
  764. }
  765. for ( ;iFirst <= iLast; iFirst++)
  766. {
  767. RECT rc;
  768. GetImageRect(iFirst, &rc);
  769. if (_GetItemFlags(iFirst) == 0)
  770. {
  771. BitBlt(_hdcImage, rc.left, rc.top, _cx, _cy,
  772. _hdcMask, rc.left, rc.top, rop);
  773. }
  774. }
  775. if (hbrT)
  776. SelectBrush(_hdcImage, hbrT);
  777. }
  778. //
  779. // GetNearestColor is problematic. If you have a 32-bit HDC with a 16-bit bitmap
  780. // selected into it, and you call GetNearestColor, GDI ignores the
  781. // color-depth of the bitmap and thinks you have a 32-bit bitmap inside,
  782. // so of course it returns the same color unchanged.
  783. //
  784. // So instead, we have to emulate GetNearestColor with SetPixel.
  785. //
  786. COLORREF GetNearestColor32(HDC hdc, COLORREF rgb)
  787. {
  788. COLORREF rgbT;
  789. rgbT = GetPixel(hdc, 0, 0);
  790. rgb = SetPixel(hdc, 0, 0, rgb);
  791. SetPixelV(hdc, 0, 0, rgbT);
  792. return rgb;
  793. }
  794. COLORREF CImageList::_SetBkColor(COLORREF clrBkI)
  795. {
  796. COLORREF clrBkOld;
  797. // Quick out if there is no change in color
  798. if (_clrBk == clrBkI)
  799. {
  800. return _clrBk;
  801. }
  802. // The following code deletes the brush, resets the background color etc.,
  803. // so, protect it with a critical section.
  804. ENTERCRITICAL;
  805. if (_hbrBk)
  806. {
  807. DeleteBrush(_hbrBk);
  808. }
  809. clrBkOld = _clrBk;
  810. _clrBk = clrBkI;
  811. if (_clrBk == CLR_NONE)
  812. {
  813. _hbrBk = (HBRUSH)GetStockObject(BLACK_BRUSH);
  814. _fSolidBk = TRUE;
  815. }
  816. else
  817. {
  818. _hbrBk = CreateSolidBrush(_clrBk);
  819. _fSolidBk = GetNearestColor32(_hdcImage, _clrBk) == _clrBk;
  820. }
  821. if (_cImage > 0)
  822. {
  823. _ResetBkColor(0, _cImage - 1, _clrBk);
  824. }
  825. LEAVECRITICAL;
  826. return clrBkOld;
  827. }
  828. HRESULT CImageList::SetBkColor(COLORREF clrBk, COLORREF* pclr)
  829. {
  830. if (_pimlMirror)
  831. {
  832. _pimlMirror->_SetBkColor(clrBk);
  833. }
  834. *pclr = _SetBkColor(clrBk);
  835. return S_OK;
  836. }
  837. HRESULT CImageList::GetBkColor(COLORREF* pclr)
  838. {
  839. *pclr = _clrBk;
  840. return S_OK;
  841. }
  842. HRESULT CImageList::_ReAllocBitmaps(int cAllocI)
  843. {
  844. HBITMAP hbmImageNew = NULL;
  845. HBITMAP hbmMaskNew = NULL;
  846. RGBQUAD* pargbImageNew = NULL;
  847. int cxL, cyL;
  848. // HACK: don't shrink unless the caller passes a negative count
  849. if (cAllocI > 0)
  850. {
  851. if (_cAlloc >= cAllocI)
  852. return S_OK;
  853. }
  854. else
  855. cAllocI *= -1;
  856. cxL = _cx * _cStrip;
  857. cyL = _cy * ((cAllocI + _cStrip - 1) / _cStrip);
  858. if (cAllocI > 0)
  859. {
  860. if (_flags & ILC_MASK)
  861. {
  862. hbmMaskNew = CreateMonoBitmap(cxL, cyL);
  863. if (!hbmMaskNew)
  864. {
  865. TraceMsg(TF_ERROR, "ImageList: Can't create bitmap");
  866. return E_OUTOFMEMORY;
  867. }
  868. }
  869. hbmImageNew = _CreateBitmap(cxL, cyL, &pargbImageNew);
  870. if (!hbmImageNew)
  871. {
  872. if (hbmMaskNew)
  873. CImageList::_DeleteBitmap(hbmMaskNew);
  874. TraceMsg(TF_ERROR, "ImageList: Can't create bitmap");
  875. return E_OUTOFMEMORY;
  876. }
  877. if (_dsaFlags == NULL)
  878. _dsaFlags = DSA_Create(sizeof(DWORD), _cGrow);
  879. if (!_dsaFlags)
  880. {
  881. if (hbmMaskNew)
  882. CImageList::_DeleteBitmap(hbmMaskNew);
  883. if (hbmImageNew)
  884. CImageList::_DeleteBitmap(hbmImageNew);
  885. TraceMsg(TF_ERROR, "ImageList: Can't create flags array");
  886. return E_OUTOFMEMORY;
  887. }
  888. }
  889. if (_cImage > 0)
  890. {
  891. int cyCopy = _cy * ((min(cAllocI, _cImage) + _cStrip - 1) / _cStrip);
  892. if (_flags & ILC_MASK)
  893. {
  894. CImageList::SelectDstBitmap(hbmMaskNew);
  895. BitBlt(g_hdcDst, 0, 0, cxL, cyCopy, _hdcMask, 0, 0, SRCCOPY);
  896. }
  897. CImageList::SelectDstBitmap(hbmImageNew);
  898. BitBlt(g_hdcDst, 0, 0, cxL, cyCopy, _hdcImage, 0, 0, SRCCOPY);
  899. }
  900. // select into DC's, delete then assign
  901. CImageList::SelectDstBitmap(NULL);
  902. CImageList::SelectSrcBitmap(NULL);
  903. SelectObject(_hdcImage, hbmImageNew);
  904. if (_hdcMask)
  905. SelectObject(_hdcMask, hbmMaskNew);
  906. if (_hbmMask)
  907. CImageList::_DeleteBitmap(_hbmMask);
  908. if (_hbmImage)
  909. CImageList::_DeleteBitmap(_hbmImage);
  910. _hbmMask = hbmMaskNew;
  911. _hbmImage = hbmImageNew;
  912. _pargbImage = pargbImageNew;
  913. _clrBlend = CLR_NONE;
  914. _cAlloc = cAllocI;
  915. return S_OK;
  916. }
  917. HBITMAP CImageList::_CreateMirroredBitmap(HBITMAP hbmOrig, BOOL fMirrorEach, int cx)
  918. {
  919. HBITMAP hbm = NULL, hOld_bm1, hOld_bm2;
  920. BITMAP bm;
  921. if (!hbmOrig)
  922. return NULL;
  923. if (!GetObject(hbmOrig, sizeof(BITMAP), &bm))
  924. return NULL;
  925. // Grab the screen DC
  926. HDC hdc = GetDC(NULL);
  927. HDC hdcMem1 = CreateCompatibleDC(hdc);
  928. if (!hdcMem1)
  929. {
  930. ReleaseDC(NULL, hdc);
  931. return NULL;
  932. }
  933. HDC hdcMem2 = CreateCompatibleDC(hdc);
  934. if (!hdcMem2)
  935. {
  936. DeleteDC(hdcMem1);
  937. ReleaseDC(NULL, hdc);
  938. return NULL;
  939. }
  940. if (bm.bmBitsPixel == 32)
  941. {
  942. void* p;
  943. BITMAPINFO bi = {sizeof(BITMAPINFOHEADER), bm.bmWidth, bm.bmHeight, 1, 32};
  944. hbm = CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, &p, NULL, 0);
  945. }
  946. else
  947. {
  948. hbm = CreateColorBitmap(bm.bmWidth, bm.bmHeight);
  949. }
  950. if (!hbm)
  951. {
  952. DeleteDC(hdcMem2);
  953. DeleteDC(hdcMem1);
  954. ReleaseDC(NULL, hdc);
  955. return NULL;
  956. }
  957. //
  958. // Flip the bitmap
  959. //
  960. hOld_bm1 = (HBITMAP)SelectObject(hdcMem1, hbmOrig);
  961. hOld_bm2 = (HBITMAP)SelectObject(hdcMem2 , hbm );
  962. SET_DC_RTL_MIRRORED(hdcMem2);
  963. if (fMirrorEach)
  964. {
  965. for (int i = 0; i < bm.bmWidth; i += cx) // Flip the bits in the imagelist...
  966. {
  967. BitBlt(hdcMem2, bm.bmWidth - i - cx, 0, cx, bm.bmHeight, hdcMem1, i, 0, SRCCOPY);
  968. }
  969. }
  970. else
  971. {
  972. BitBlt(hdcMem2, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem1, 0, 0, SRCCOPY);
  973. }
  974. SelectObject(hdcMem1, hOld_bm1 );
  975. SelectObject(hdcMem1, hOld_bm2 );
  976. DeleteDC(hdcMem2);
  977. DeleteDC(hdcMem1);
  978. ReleaseDC(NULL, hdc);
  979. return hbm;
  980. }
  981. HRESULT CImageList::SetColorTable(int start, int len, RGBQUAD *prgb, int* pi)
  982. {
  983. // mark it that we have set the color table so that it won't be overwritten
  984. // by the first bitmap add....
  985. _fColorsSet = TRUE;
  986. if (_hdcImage)
  987. {
  988. *pi = SetDIBColorTable(_hdcImage, start, len, prgb);
  989. return S_OK;
  990. }
  991. return E_FAIL;
  992. }
  993. BOOL CImageList::_HasAlpha(int i)
  994. {
  995. if ((_flags & ILC_COLORMASK) == ILC_COLOR32)
  996. {
  997. RECT rc;
  998. if (SUCCEEDED(GetImageRectInverted(i, &rc)))
  999. {
  1000. for (int y = rc.top; y < rc.bottom; y++)
  1001. {
  1002. for (int x = rc.left; x < rc.right; x++)
  1003. {
  1004. if (_pargbImage[x + y * _cx].rgbReserved != 0)
  1005. return TRUE;
  1006. }
  1007. }
  1008. }
  1009. }
  1010. return FALSE;
  1011. }
  1012. void CImageList::_ScanForAlpha()
  1013. {
  1014. if ((_flags & ILC_COLORMASK) == ILC_COLOR32)
  1015. {
  1016. for (int i = 0; i < _cImage; i++)
  1017. {
  1018. SetItemFlags(i, _HasAlpha(i)? ILIF_ALPHA : 0);
  1019. }
  1020. }
  1021. }
  1022. BOOL CImageList::_PreProcessImage(int i)
  1023. {
  1024. if ((_flags & ILC_COLORMASK) == ILC_COLOR32)
  1025. {
  1026. RECT rc;
  1027. GetImageRectInverted(i, &rc);
  1028. #ifdef _X86_
  1029. if (IsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE))
  1030. {
  1031. _asm
  1032. {
  1033. pxor mm0, mm0
  1034. pxor mm1, mm1
  1035. pxor mm5, mm5
  1036. movq mm6, qw128 // mm6 is filled with 128
  1037. movq mm7, qw1 // mm7 is filled with 1
  1038. }
  1039. for (int y = rc.top; y < rc.bottom; y++)
  1040. {
  1041. int Offset = y * _cx;
  1042. RGBQUAD* prgb = &_pargbImage[rc.left + Offset];
  1043. for (int x = rc.left; x < rc.right; x++)
  1044. {
  1045. _asm
  1046. {
  1047. push ecx
  1048. mov edx, dword ptr [prgb] // Read alpha channel
  1049. mov ecx, dword ptr [edx]
  1050. mov ebx, ecx
  1051. shr ebx, 24 // a >> 24
  1052. mov eax, ebx // a -> b
  1053. or eax, eax
  1054. jz EarlyOut
  1055. shl ebx, 8 // b << 8
  1056. or eax, ebx // a |= b
  1057. shl ebx, 8 // b << 8
  1058. or eax, ebx // a |= b
  1059. shl ebx, 8 // b << 8
  1060. // Note high byte of alpha is zero.
  1061. movd mm0, eax // a -> mm0
  1062. movd mm1, ecx // Load the pixel
  1063. punpcklbw mm0,mm5 // mm0 -> Expands <- mm0 Contains the Alpha channel for this multiply
  1064. punpcklbw mm1,mm5 // Unpack the pixel
  1065. pmullw mm1, mm0 // Multiply by the alpha channel <- mm1 contains c * alpha
  1066. paddusw mm1, mm6 // perform the (c * alpha) + 128
  1067. psrlw mm1, 8 // Divide by 255
  1068. paddusw mm1, mm7 // Add 1 to finish the divide by 255
  1069. packuswb mm1, mm5
  1070. movd eax, mm1
  1071. or eax, ebx // Transfer alpha channel
  1072. EarlyOut:
  1073. mov dword ptr [edx], eax
  1074. pop ecx
  1075. }
  1076. prgb++;
  1077. }
  1078. }
  1079. _asm emms
  1080. }
  1081. else
  1082. #endif
  1083. {
  1084. for (int y = rc.top; y < rc.bottom; y++)
  1085. {
  1086. int Offset = y * _cx;
  1087. for (int x = rc.left; x < rc.right; x++)
  1088. {
  1089. RGBQUAD* prgb = &_pargbImage[x + Offset];
  1090. if (prgb->rgbReserved)
  1091. {
  1092. prgb->rgbRed = ((prgb->rgbRed * prgb->rgbReserved) + 128) / 255;
  1093. prgb->rgbGreen = ((prgb->rgbGreen * prgb->rgbReserved) + 128) / 255;
  1094. prgb->rgbBlue = ((prgb->rgbBlue * prgb->rgbReserved) + 128) / 255;
  1095. }
  1096. else
  1097. {
  1098. *((DWORD*)prgb) = 0;
  1099. }
  1100. }
  1101. }
  1102. }
  1103. return TRUE;
  1104. }
  1105. return FALSE;
  1106. }
  1107. HRESULT CImageList::_Add(HBITMAP hbmImageI, HBITMAP hbmMaskI, int cImageI, int xStart, int yStart, int* pi)
  1108. {
  1109. int i = -1;
  1110. HRESULT hr = S_OK;
  1111. ENTERCRITICAL;
  1112. //
  1113. // if the ImageList is empty clone the color table of the first
  1114. // bitmap you add to the imagelist.
  1115. //
  1116. // the ImageList needs to be a 8bpp image list
  1117. // the bitmap being added needs to be a 8bpp DIBSection
  1118. //
  1119. if (hbmImageI && _cImage == 0 &&
  1120. (_flags & ILC_COLORMASK) != ILC_COLORDDB)
  1121. {
  1122. if (!_fColorsSet)
  1123. {
  1124. int n;
  1125. RGBQUAD argb[256];
  1126. CImageList::SelectDstBitmap(hbmImageI);
  1127. if (n = GetDIBColorTable(g_hdcDst, 0, 256, argb))
  1128. {
  1129. int i;
  1130. SetColorTable(0, n, argb, &i);
  1131. }
  1132. CImageList::SelectDstBitmap(NULL);
  1133. }
  1134. _clrBlend = CLR_NONE;
  1135. }
  1136. if (_cImage + cImageI + 1 > _cAlloc)
  1137. {
  1138. hr = _ReAllocBitmaps(_cAlloc + max(cImageI, _cGrow) + 1);
  1139. }
  1140. if (SUCCEEDED(hr))
  1141. {
  1142. i = _cImage;
  1143. _cImage += cImageI;
  1144. if (hbmImageI)
  1145. {
  1146. hr = _Replace(i, cImageI, hbmImageI, hbmMaskI, xStart, yStart);
  1147. if (FAILED(hr))
  1148. {
  1149. _cImage -= cImageI;
  1150. i = -1;
  1151. }
  1152. }
  1153. }
  1154. LEAVECRITICAL;
  1155. *pi = i;
  1156. return hr;
  1157. }
  1158. HRESULT CImageList::_AddValidated(HBITMAP hbmImage, HBITMAP hbmMask, int* pi)
  1159. {
  1160. BITMAP bm;
  1161. int cImageI;
  1162. if (GetObject(hbmImage, sizeof(bm), &bm) != sizeof(bm) || bm.bmWidth < _cx)
  1163. {
  1164. return E_INVALIDARG;
  1165. }
  1166. ASSERT(hbmImage);
  1167. ASSERT(_cx);
  1168. cImageI = bm.bmWidth / _cx; // # of images in source
  1169. // serialization handled within Add2.
  1170. return _Add(hbmImage, hbmMask, cImageI, 0, 0, pi);
  1171. }
  1172. HRESULT CImageList::Add(HBITMAP hbmImage, HBITMAP hbmMask, int* pi)
  1173. {
  1174. if (_pimlMirror)
  1175. {
  1176. HBITMAP hbmMirroredImage = _CreateMirroredBitmap(hbmImage, (ILC_PERITEMMIRROR & _flags), _cx);
  1177. HBITMAP hbmMirroredMask = _CreateMirroredBitmap(hbmMask, (ILC_PERITEMMIRROR & _flags), _cx);
  1178. _pimlMirror->_AddValidated(hbmMirroredImage, hbmMirroredMask, pi);
  1179. // The caller will take care of deleting hbmImage, hbmMask
  1180. // He knows nothing about hbmMirroredImage, hbmMirroredMask
  1181. DeleteObject(hbmMirroredImage);
  1182. DeleteObject(hbmMirroredMask);
  1183. }
  1184. return _AddValidated(hbmImage, hbmMask, pi);
  1185. }
  1186. HRESULT CImageList::_AddMasked(HBITMAP hbmImageI, COLORREF crMask, int* pi)
  1187. {
  1188. HRESULT hr = S_OK;
  1189. COLORREF crbO, crtO;
  1190. HBITMAP hbmMaskI;
  1191. int cImageI;
  1192. int n,i;
  1193. BITMAP bm;
  1194. DWORD ColorTableSave[256];
  1195. DWORD ColorTable[256];
  1196. *pi = -1;
  1197. if (GetObject(hbmImageI, sizeof(bm), &bm) != sizeof(bm))
  1198. return E_INVALIDARG;
  1199. hbmMaskI = CreateMonoBitmap(bm.bmWidth, bm.bmHeight);
  1200. if (!hbmMaskI)
  1201. return E_OUTOFMEMORY;
  1202. ENTERCRITICAL;
  1203. // copy color to mono, with crMask turning 1 and all others 0, then
  1204. // punch all crMask pixels in color to 0
  1205. CImageList::SelectSrcBitmap(hbmImageI);
  1206. CImageList::SelectDstBitmap(hbmMaskI);
  1207. // crMask == CLR_DEFAULT, means use the pixel in the upper left
  1208. //
  1209. if (crMask == CLR_DEFAULT)
  1210. crMask = GetPixel(g_hdcSrc, 0, 0);
  1211. // DIBSections dont do color->mono like DDBs do, so we have to do it.
  1212. // this only works for <=8bpp DIBSections, this method does not work
  1213. // for HiColor DIBSections.
  1214. //
  1215. // This code is a workaround for a problem in Win32 when a DIB is converted to
  1216. // monochrome. The conversion is done according to closeness to white or black
  1217. // and without regard to the background color. This workaround is is not required
  1218. // under MainWin.
  1219. //
  1220. // Please note, this code has an endianship problems the comparision in the if statement
  1221. // below is sensitive to endianship
  1222. // ----> if (ColorTableSave[i] == RGB(GetBValue(crMask),GetGValue(crMask),GetRValue(crMask))
  1223. //
  1224. if (bm.bmBits != NULL && bm.bmBitsPixel <= 8)
  1225. {
  1226. n = GetDIBColorTable(g_hdcSrc, 0, 256, (RGBQUAD*)ColorTableSave);
  1227. for (i=0; i<n; i++)
  1228. {
  1229. if (ColorTableSave[i] == RGB(GetBValue(crMask),GetGValue(crMask),GetRValue(crMask)))
  1230. ColorTable[i] = 0x00FFFFFF;
  1231. else
  1232. ColorTable[i] = 0x00000000;
  1233. }
  1234. SetDIBColorTable(g_hdcSrc, 0, n, (RGBQUAD*)ColorTable);
  1235. }
  1236. crbO = ::SetBkColor(g_hdcSrc, crMask);
  1237. BitBlt(g_hdcDst, 0, 0, bm.bmWidth, bm.bmHeight, g_hdcSrc, 0, 0, SRCCOPY);
  1238. ::SetBkColor(g_hdcSrc, 0x00FFFFFFL);
  1239. crtO = SetTextColor(g_hdcSrc, 0x00L);
  1240. BitBlt(g_hdcSrc, 0, 0, bm.bmWidth, bm.bmHeight, g_hdcDst, 0, 0, ROP_DSna);
  1241. ::SetBkColor(g_hdcSrc, crbO);
  1242. SetTextColor(g_hdcSrc, crtO);
  1243. if (bm.bmBits != NULL && bm.bmBitsPixel <= 8)
  1244. {
  1245. SetDIBColorTable(g_hdcSrc, 0, n, (RGBQUAD*)ColorTableSave);
  1246. }
  1247. CImageList::SelectSrcBitmap(NULL);
  1248. CImageList::SelectDstBitmap(NULL);
  1249. ASSERT(_cx);
  1250. cImageI = bm.bmWidth / _cx; // # of images in source
  1251. hr = _Add(hbmImageI, hbmMaskI, cImageI, 0, 0, pi);
  1252. DeleteObject(hbmMaskI);
  1253. LEAVECRITICAL;
  1254. return hr;
  1255. }
  1256. HRESULT CImageList::AddMasked(HBITMAP hbmImage, COLORREF crMask, int* pi)
  1257. {
  1258. if (_pimlMirror)
  1259. {
  1260. HBITMAP hbmMirroredImage = CImageList::_CreateMirroredBitmap(hbmImage, (ILC_PERITEMMIRROR & _flags), _cx);
  1261. _pimlMirror->_AddMasked(hbmMirroredImage, crMask, pi);
  1262. // The caller will take care of deleting hbmImage
  1263. // He knows nothing about hbmMirroredImage
  1264. DeleteObject(hbmMirroredImage);
  1265. }
  1266. return _AddMasked(hbmImage, crMask, pi);
  1267. }
  1268. HRESULT CImageList::_ReplaceValidated(int i, HBITMAP hbmImage, HBITMAP hbmMask)
  1269. {
  1270. HRESULT hr = E_INVALIDARG;
  1271. if (!IsImageListIndex(i))
  1272. return hr;
  1273. ENTERCRITICAL;
  1274. hr = _Replace(i, 1, hbmImage, hbmMask, 0, 0);
  1275. LEAVECRITICAL;
  1276. return hr;
  1277. }
  1278. HRESULT CImageList::Replace(int i, HBITMAP hbmImage, HBITMAP hbmMask)
  1279. {
  1280. if (_pimlMirror)
  1281. {
  1282. HBITMAP hbmMirroredImage = CImageList::_CreateMirroredBitmap(hbmImage, (ILC_PERITEMMIRROR & _flags), _cx);
  1283. if (hbmMirroredImage)
  1284. {
  1285. HBITMAP hbmMirroredMask = NULL;
  1286. if (hbmMask)
  1287. hbmMirroredMask = CImageList::_CreateMirroredBitmap(hbmMask, (ILC_PERITEMMIRROR & _flags), _cx);
  1288. _pimlMirror->_ReplaceValidated(i, hbmMirroredImage, hbmMirroredMask);
  1289. if (hbmMirroredMask)
  1290. DeleteObject(hbmMirroredMask);
  1291. DeleteObject(hbmMirroredImage);
  1292. }
  1293. }
  1294. return _ReplaceValidated(i, hbmImage, hbmMask);
  1295. }
  1296. // replaces images in piml with images from bitmaps
  1297. //
  1298. // in:
  1299. // piml
  1300. // i index in image list to start at (replace)
  1301. // _cImage count of images in source (hbmImage, hbmMask)
  1302. //
  1303. HRESULT CImageList::_Replace(int i, int cImageI, HBITMAP hbmImageI, HBITMAP hbmMaskI,
  1304. int xStart, int yStart)
  1305. {
  1306. RECT rcImage;
  1307. int x, iImage;
  1308. BOOL fBitmapIs32 = FALSE;
  1309. ASSERT(_hbmImage);
  1310. BITMAP bm;
  1311. GetObject(hbmImageI, sizeof(bm), &bm);
  1312. if (bm.bmBitsPixel == 32)
  1313. {
  1314. fBitmapIs32 = TRUE;
  1315. }
  1316. CImageList::SelectSrcBitmap(hbmImageI);
  1317. if (_hdcMask)
  1318. CImageList::SelectDstBitmap(hbmMaskI); // using as just a second source hdc
  1319. for (x = xStart, iImage = 0; iImage < cImageI; iImage++, x += _cx)
  1320. {
  1321. GetImageRect(i + iImage, &rcImage);
  1322. if (_hdcMask)
  1323. {
  1324. BitBlt(_hdcMask, rcImage.left, rcImage.top, _cx, _cy,
  1325. g_hdcDst, x, yStart, SRCCOPY);
  1326. }
  1327. BitBlt(_hdcImage, rcImage.left, rcImage.top, _cx, _cy,
  1328. g_hdcSrc, x, yStart, SRCCOPY);
  1329. if ((_flags & ILC_COLORMASK) == ILC_COLOR32)
  1330. {
  1331. DWORD dw = 0;
  1332. if (fBitmapIs32)
  1333. {
  1334. BOOL fHasAlpha = _HasAlpha(i + iImage);
  1335. if (fHasAlpha)
  1336. {
  1337. dw = ILIF_ALPHA;
  1338. _PreProcessImage(i + iImage);
  1339. }
  1340. }
  1341. SetItemFlags(i + iImage, dw);
  1342. }
  1343. }
  1344. _ResetBkColor(i, i + cImageI - 1, _clrBk);
  1345. CImageList::SelectSrcBitmap(NULL);
  1346. if (_hdcMask)
  1347. CImageList::SelectDstBitmap(NULL);
  1348. return S_OK;
  1349. }
  1350. void UnPremultiply(RGBQUAD* pargb, int cx, int cy)
  1351. {
  1352. int cTotal = cx * cy;
  1353. for (int i = 0; i < cTotal; i++)
  1354. {
  1355. RGBQUAD* prgb = &pargb[i];
  1356. if (prgb->rgbReserved != 0)
  1357. {
  1358. prgb->rgbRed = ((255 * prgb->rgbRed) - 128)/prgb->rgbReserved;
  1359. prgb->rgbGreen = ((255 * prgb->rgbGreen) - 128)/prgb->rgbReserved;
  1360. prgb->rgbBlue = ((255 * prgb->rgbBlue) - 128)/prgb->rgbReserved;
  1361. }
  1362. }
  1363. }
  1364. HRESULT CImageList::GetIcon(int i, UINT flags, HICON* phicon)
  1365. {
  1366. UINT cxImage, cyImage;
  1367. HICON hIcon = NULL;
  1368. HBITMAP hbmMask = NULL;
  1369. HBITMAP hbmColor = NULL;
  1370. ICONINFO ii;
  1371. HRESULT hr = E_OUTOFMEMORY;
  1372. RGBQUAD* prgb;
  1373. DWORD fHasAlpha = FALSE;
  1374. ENTERCRITICAL;
  1375. if (!IsImageListIndex(i))
  1376. {
  1377. hr = E_INVALIDARG;
  1378. }
  1379. else
  1380. {
  1381. fHasAlpha = (_GetItemFlags(i) & ILIF_ALPHA);
  1382. }
  1383. LEAVECRITICAL;
  1384. if (E_INVALIDARG == hr)
  1385. return hr;
  1386. cxImage = _cx;
  1387. cyImage = _cy;
  1388. if ((_flags & ILC_COLORMASK) == ILC_COLOR32)
  1389. {
  1390. // If the source image is not an alpha image, we need to create a lower than 32bpp dib.
  1391. // We need to do this because if the overlay contains an alpha channel, this will
  1392. // be propogated to the final icon, and the only visible portion will be the link item.
  1393. BITMAPINFO bi = {0};
  1394. bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
  1395. bi.bmiHeader.biWidth = cxImage;
  1396. bi.bmiHeader.biHeight = cyImage;
  1397. bi.bmiHeader.biPlanes = 1;
  1398. bi.bmiHeader.biBitCount = fHasAlpha?32:24;
  1399. bi.bmiHeader.biCompression = BI_RGB;
  1400. HDC hdcScreen = GetDC(NULL);
  1401. if (hdcScreen)
  1402. {
  1403. hbmColor = CreateDIBSection(hdcScreen, &bi, DIB_RGB_COLORS, (void**)&prgb, NULL, 0);
  1404. ReleaseDC(NULL, hdcScreen);
  1405. }
  1406. flags |= ILD_PRESERVEALPHA;
  1407. }
  1408. else
  1409. {
  1410. fHasAlpha = FALSE;
  1411. hbmColor = CreateColorBitmap(cxImage, cyImage);
  1412. }
  1413. if (hbmColor)
  1414. {
  1415. hbmMask = CreateMonoBitmap(cxImage, cyImage);
  1416. if (hbmMask)
  1417. {
  1418. ENTERCRITICAL;
  1419. CImageList::SelectDstBitmap(hbmMask);
  1420. PatBlt(g_hdcDst, 0, 0, cxImage, cyImage, WHITENESS);
  1421. WimpyDraw(SAFECAST(this, IImageList*), i, g_hdcDst, 0, 0, ILD_MASK | flags);
  1422. CImageList::SelectDstBitmap(hbmColor);
  1423. PatBlt(g_hdcDst, 0, 0, cxImage, cyImage, BLACKNESS);
  1424. WimpyDraw(SAFECAST(this, IImageList*), i, g_hdcDst, 0, 0, ILD_TRANSPARENT | flags);
  1425. CImageList::SelectDstBitmap(NULL);
  1426. LEAVECRITICAL;
  1427. if (fHasAlpha)
  1428. {
  1429. UnPremultiply(prgb, _cx, _cy);
  1430. }
  1431. ii.fIcon = TRUE;
  1432. ii.xHotspot = 0;
  1433. ii.yHotspot = 0;
  1434. ii.hbmColor = hbmColor;
  1435. ii.hbmMask = hbmMask;
  1436. hIcon = CreateIconIndirect(&ii);
  1437. DeleteObject(hbmMask);
  1438. hr = S_OK;
  1439. }
  1440. DeleteObject(hbmColor);
  1441. }
  1442. *phicon = hIcon;
  1443. return hr;
  1444. }
  1445. // this removes an image from the bitmap but doing all the
  1446. // proper shuffling.
  1447. //
  1448. // this does the following:
  1449. // if the bitmap being removed is not the last in the row
  1450. // it blts the images to the right of the one being deleted
  1451. // to the location of the one being deleted (covering it up)
  1452. //
  1453. // for all rows until the last row (where the last image is)
  1454. // move the image from the next row up to the last position
  1455. // in the current row. then slide over all images in that
  1456. // row to the left.
  1457. void CImageList::_RemoveItemBitmap(int i)
  1458. {
  1459. RECT rc1;
  1460. RECT rc2;
  1461. int dx, y;
  1462. int x;
  1463. GetImageRect(i, &rc1);
  1464. GetImageRect(_cImage - 1, &rc2);
  1465. if (i < _cImage &&
  1466. (_flags & ILC_COLORMASK) == ILC_COLOR32)
  1467. {
  1468. DSA_DeleteItem(_dsaFlags, i);
  1469. }
  1470. SetItemFlags(_cImage, 0);
  1471. // the row with the image being deleted, do we need to shuffle?
  1472. // amount of stuff to shuffle
  1473. dx = _cStrip * _cx - rc1.right;
  1474. if (dx)
  1475. {
  1476. // yes, shuffle things left
  1477. BitBlt(_hdcImage, rc1.left, rc1.top, dx, _cy, _hdcImage, rc1.right, rc1.top, SRCCOPY);
  1478. if (_hdcMask)
  1479. BitBlt(_hdcMask, rc1.left, rc1.top, dx, _cy, _hdcMask, rc1.right, rc1.top, SRCCOPY);
  1480. }
  1481. y = rc1.top; // top of row we are working on
  1482. x = _cx * (_cStrip - 1); // x coord of last bitmaps in each row
  1483. while (y < rc2.top)
  1484. {
  1485. // copy first from row below to last image position on this row
  1486. BitBlt(_hdcImage, x, y,
  1487. _cx, _cy, _hdcImage, 0, y + _cy, SRCCOPY);
  1488. if (_hdcMask)
  1489. BitBlt(_hdcMask, x, y,
  1490. _cx, _cy, _hdcMask, 0, y + _cy, SRCCOPY);
  1491. y += _cy; // jump to row to slide left
  1492. if (y <= rc2.top)
  1493. {
  1494. // slide the rest over to the left
  1495. BitBlt(_hdcImage, 0, y, x, _cy,
  1496. _hdcImage, _cx, y, SRCCOPY);
  1497. // slide the rest over to the left
  1498. if (_hdcMask)
  1499. {
  1500. BitBlt(_hdcMask, 0, y, x, _cy,
  1501. _hdcMask, _cx, y, SRCCOPY);
  1502. }
  1503. }
  1504. }
  1505. }
  1506. //
  1507. // ImageList_Remove - remove a image from the image list
  1508. //
  1509. // i - image to remove, or -1 to remove all images.
  1510. //
  1511. // NOTE all images are "shifted" down, ie all image index's
  1512. // above the one deleted are changed by 1
  1513. //
  1514. HRESULT CImageList::_Remove(int i)
  1515. {
  1516. HRESULT hr = S_OK;
  1517. ENTERCRITICAL;
  1518. if (i == -1)
  1519. {
  1520. _cImage = 0;
  1521. _cAlloc = 0;
  1522. for (i=0; i<NUM_OVERLAY_IMAGES; i++)
  1523. _aOverlayIndexes[i] = -1;
  1524. if (_dsaFlags)
  1525. {
  1526. DSA_Destroy(_dsaFlags);
  1527. _dsaFlags = NULL;
  1528. }
  1529. _ReAllocBitmaps(-_cGrow);
  1530. }
  1531. else
  1532. {
  1533. if (!IsImageListIndex(i))
  1534. {
  1535. hr = E_INVALIDARG;
  1536. }
  1537. else
  1538. {
  1539. _RemoveItemBitmap(i);
  1540. --_cImage;
  1541. if (_cAlloc - (_cImage + 1) > _cGrow)
  1542. _ReAllocBitmaps(_cAlloc - _cGrow);
  1543. }
  1544. }
  1545. LEAVECRITICAL;
  1546. return hr;
  1547. }
  1548. HRESULT CImageList::Remove(int i)
  1549. {
  1550. if (_pimlMirror)
  1551. {
  1552. _pimlMirror->_Remove(i);
  1553. }
  1554. return _Remove(i);
  1555. }
  1556. BOOL CImageList::_IsSameObject(IUnknown* punk)
  1557. {
  1558. BOOL fRet = FALSE;
  1559. IUnknown* me;
  1560. IUnknown* them;
  1561. if (punk == NULL)
  1562. return FALSE;
  1563. QueryInterface(IID_PPV_ARG(IUnknown, &me));
  1564. if (SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IUnknown, &them))))
  1565. {
  1566. fRet = (me == them);
  1567. them->Release();
  1568. }
  1569. me->Release();
  1570. return fRet;
  1571. }
  1572. //
  1573. // ImageList_Copy - move an image in the image list
  1574. //
  1575. HRESULT CImageList::Copy(int iDst, IUnknown* punkSrc, int iSrc, UINT uFlags)
  1576. {
  1577. RECT rcDst, rcSrc, rcTmp;
  1578. CImageList* pimlTmp;
  1579. CImageList* pimlSrc;
  1580. HRESULT hr = E_FAIL;
  1581. if (uFlags & ~ILCF_VALID)
  1582. {
  1583. // don't let hosers pass bogus flags
  1584. RIPMSG(0, "ImageList_Copy: Invalid flags %08x", uFlags);
  1585. return E_INVALIDARG;
  1586. }
  1587. // Not supported
  1588. if (!_IsSameObject(punkSrc))
  1589. {
  1590. return E_INVALIDARG;
  1591. }
  1592. // We only support copies on ourself... Weird
  1593. pimlSrc = this;
  1594. ENTERCRITICAL;
  1595. pimlTmp = (uFlags & ILCF_SWAP)? pimlSrc : NULL;
  1596. if (SUCCEEDED(GetImageRect(iDst, &rcDst)) &&
  1597. SUCCEEDED(pimlSrc->GetImageRect(iSrc, &rcSrc)) &&
  1598. (!pimlTmp || pimlTmp->GetSpareImageRect(&rcTmp)))
  1599. {
  1600. int cx = pimlSrc->_cx;
  1601. int cy = pimlSrc->_cy;
  1602. //
  1603. // iff we are swapping we need to save the destination image
  1604. //
  1605. if (pimlTmp)
  1606. {
  1607. BitBlt(pimlTmp->_hdcImage, rcTmp.left, rcTmp.top, cx, cy,
  1608. _hdcImage, rcDst.left, rcDst.top, SRCCOPY);
  1609. if (pimlTmp->_hdcMask)
  1610. {
  1611. BitBlt(pimlTmp->_hdcMask, rcTmp.left, rcTmp.top, cx, cy,
  1612. _hdcMask, rcDst.left, rcDst.top, SRCCOPY);
  1613. }
  1614. }
  1615. //
  1616. // copy the image
  1617. //
  1618. BitBlt(_hdcImage, rcDst.left, rcDst.top, cx, cy,
  1619. pimlSrc->_hdcImage, rcSrc.left, rcSrc.top, SRCCOPY);
  1620. if (pimlSrc->_hdcMask)
  1621. {
  1622. BitBlt(_hdcMask, rcDst.left, rcDst.top, cx, cy,
  1623. pimlSrc->_hdcMask, rcSrc.left, rcSrc.top, SRCCOPY);
  1624. }
  1625. //
  1626. // iff we are swapping we need to copy the saved image too
  1627. //
  1628. if (pimlTmp)
  1629. {
  1630. BitBlt(pimlSrc->_hdcImage, rcSrc.left, rcSrc.top, cx, cy,
  1631. pimlTmp->_hdcImage, rcTmp.left, rcTmp.top, SRCCOPY);
  1632. if (pimlSrc->_hdcMask)
  1633. {
  1634. BitBlt(pimlSrc->_hdcMask, rcSrc.left, rcSrc.top, cx, cy,
  1635. pimlTmp->_hdcMask, rcTmp.left, rcTmp.top, SRCCOPY);
  1636. }
  1637. }
  1638. hr = S_OK;
  1639. }
  1640. LEAVECRITICAL;
  1641. return hr;
  1642. }
  1643. // IS_WHITE_PIXEL, BITS_ALL_WHITE are macros for looking at monochrome bits
  1644. // to determine if certain pixels are white or black. Note that within a byte
  1645. // the most significant bit represents the left most pixel.
  1646. //
  1647. #define IS_WHITE_PIXEL(pj,x,y,cScan) \
  1648. ((pj)[((y) * (cScan)) + ((x) >> 3)] & (1 << (7 - ((x) & 7))))
  1649. #define BITS_ALL_WHITE(b) (b == 0xff)
  1650. // Set the image iImage as one of the special images for us in combine
  1651. // drawing. to draw with these specify the index of this
  1652. // in:
  1653. // piml imagelist
  1654. // iImage image index to use in speical drawing
  1655. // iOverlay index of special image, values 1-4
  1656. HRESULT CImageList::_SetOverlayImage(int iImage, int iOverlay)
  1657. {
  1658. RECT rcImage;
  1659. RECT rc;
  1660. int x,y;
  1661. int cxI,cyI;
  1662. ULONG cScan;
  1663. ULONG cBits;
  1664. HBITMAP hbmMem;
  1665. HRESULT hr = S_FALSE;
  1666. iOverlay--; // make zero based
  1667. if (_hdcMask == NULL ||
  1668. iImage < 0 || iImage >= _cImage ||
  1669. iOverlay < 0 || iOverlay >= NUM_OVERLAY_IMAGES)
  1670. {
  1671. return E_INVALIDARG;
  1672. }
  1673. if (_aOverlayIndexes[iOverlay] == (SHORT)iImage)
  1674. return S_OK;
  1675. _aOverlayIndexes[iOverlay] = (SHORT)iImage;
  1676. //
  1677. // find minimal rect that bounds the image
  1678. //
  1679. GetImageRect(iImage, &rcImage);
  1680. SetRect(&rc, 0x7FFF, 0x7FFF, 0, 0);
  1681. //
  1682. // now compute the black box. This is much faster than GetPixel but
  1683. // could still be improved by doing more operations looking at entire
  1684. // bytes. We basicaly get the bits in monochrome form and then use
  1685. // a private GetPixel. This decreased time on NT from 50 milliseconds to
  1686. // 1 millisecond for a 32X32 image.
  1687. //
  1688. cxI = rcImage.right - rcImage.left;
  1689. cyI = rcImage.bottom - rcImage.top;
  1690. // compute the number of bytes in a scan. Note that they are WORD alligned
  1691. cScan = (((cxI + (sizeof(SHORT)*8 - 1)) / 16) * 2);
  1692. cBits = cScan * cyI;
  1693. hbmMem = CreateMonoBitmap(cxI,cyI);
  1694. if (hbmMem)
  1695. {
  1696. HDC hdcMem = CreateCompatibleDC(_hdcMask);
  1697. if (hdcMem)
  1698. {
  1699. PBYTE pBits = (PBYTE)LocalAlloc(LMEM_FIXED,cBits);
  1700. PBYTE pScan;
  1701. if (pBits)
  1702. {
  1703. SelectObject(hdcMem,hbmMem);
  1704. //
  1705. // map black pixels to 0, white to 1
  1706. //
  1707. BitBlt(hdcMem, 0, 0, cxI, cyI, _hdcMask, rcImage.left, rcImage.top, SRCCOPY);
  1708. //
  1709. // fill in the bits
  1710. //
  1711. GetBitmapBits(hbmMem,cBits,pBits);
  1712. //
  1713. // for each scan, find the bounds
  1714. //
  1715. for (y = 0, pScan = pBits; y < cyI; ++y,pScan += cScan)
  1716. {
  1717. int i;
  1718. //
  1719. // first go byte by byte through white space
  1720. //
  1721. for (x = 0, i = 0; (i < (cxI >> 3)) && BITS_ALL_WHITE(pScan[i]); ++i)
  1722. {
  1723. x += 8;
  1724. }
  1725. //
  1726. // now finish the scan bit by bit
  1727. //
  1728. for (; x < cxI; ++x)
  1729. {
  1730. if (!IS_WHITE_PIXEL(pBits, x,y,cScan))
  1731. {
  1732. rc.left = min(rc.left, x);
  1733. rc.right = max(rc.right, x+1);
  1734. rc.top = min(rc.top, y);
  1735. rc.bottom = max(rc.bottom, y+1);
  1736. // now that we found one, quickly jump to the known right edge
  1737. if ((x >= rc.left) && (x < rc.right))
  1738. {
  1739. x = rc.right-1;
  1740. }
  1741. }
  1742. }
  1743. }
  1744. if (rc.left == 0x7FFF)
  1745. {
  1746. rc.left = 0;
  1747. TraceMsg(TF_ERROR, "SetOverlayImage: Invalid image. No white pixels specified");
  1748. }
  1749. if (rc.top == 0x7FFF)
  1750. {
  1751. rc.top = 0;
  1752. TraceMsg(TF_ERROR, "SetOverlayImage: Invalid image. No white pixels specified");
  1753. }
  1754. _aOverlayDX[iOverlay] = (SHORT)(rc.right - rc.left);
  1755. _aOverlayDY[iOverlay] = (SHORT)(rc.bottom- rc.top);
  1756. _aOverlayX[iOverlay] = (SHORT)(rc.left);
  1757. _aOverlayY[iOverlay] = (SHORT)(rc.top);
  1758. _aOverlayF[iOverlay] = 0;
  1759. //
  1760. // see if the image is non-rectanglar
  1761. //
  1762. // if the overlay does not require a mask to be drawn set the
  1763. // ILD_IMAGE flag, this causes ImageList_DrawEx to just
  1764. // draw the image, ignoring the mask.
  1765. //
  1766. for (y=rc.top; y<rc.bottom; y++)
  1767. {
  1768. for (x=rc.left; x<rc.right; x++)
  1769. {
  1770. if (IS_WHITE_PIXEL(pBits, x, y,cScan))
  1771. break;
  1772. }
  1773. if (x != rc.right)
  1774. break;
  1775. }
  1776. if (y == rc.bottom)
  1777. _aOverlayF[iOverlay] = ILD_IMAGE;
  1778. LocalFree(pBits);
  1779. hr = S_OK;
  1780. }
  1781. DeleteDC(hdcMem);
  1782. }
  1783. DeleteObject(hbmMem);
  1784. }
  1785. return hr;
  1786. }
  1787. HRESULT CImageList::SetOverlayImage(int iImage, int iOverlay)
  1788. {
  1789. if (_pimlMirror)
  1790. {
  1791. _pimlMirror->_SetOverlayImage(iImage, iOverlay);
  1792. }
  1793. return _SetOverlayImage(iImage, iOverlay);
  1794. }
  1795. /*
  1796. ** BlendCT
  1797. **
  1798. */
  1799. void CImageList::BlendCTHelper(DWORD *pdw, DWORD rgb, UINT n, UINT count)
  1800. {
  1801. UINT i;
  1802. for (i=0; i<count; i++)
  1803. {
  1804. pdw[i] = RGB(
  1805. ((UINT)GetRValue(pdw[i]) * (100-n) + (UINT)GetBValue(rgb) * (n)) / 100,
  1806. ((UINT)GetGValue(pdw[i]) * (100-n) + (UINT)GetGValue(rgb) * (n)) / 100,
  1807. ((UINT)GetBValue(pdw[i]) * (100-n) + (UINT)GetRValue(rgb) * (n)) / 100);
  1808. }
  1809. }
  1810. /*
  1811. ** BlendDither
  1812. **
  1813. ** copy the source to the dest blended with the given color.
  1814. **
  1815. ** simulate a blend with a dither pattern.
  1816. **
  1817. */
  1818. void CImageList::BlendDither(HDC hdcDst, int xDst, int yDst, int x, int y, int cx, int cy, COLORREF rgb, UINT fStyle)
  1819. {
  1820. HBRUSH hbr;
  1821. HBRUSH hbrT;
  1822. HBRUSH hbrMask;
  1823. HBRUSH hbrFree = NULL; // free if non-null
  1824. ASSERT(GetTextColor(hdcDst) == CLR_BLACK);
  1825. ASSERT(::GetBkColor(hdcDst) == CLR_WHITE);
  1826. // choose a dither/blend brush
  1827. switch (fStyle & ILD_BLENDMASK)
  1828. {
  1829. default:
  1830. case ILD_BLEND50:
  1831. hbrMask = g_hbrMonoDither;
  1832. break;
  1833. }
  1834. // create (or use a existing) brush for the blend color
  1835. switch (rgb)
  1836. {
  1837. case CLR_DEFAULT:
  1838. hbr = g_hbrHighlight;
  1839. break;
  1840. case CLR_NONE:
  1841. hbr = _hbrBk;
  1842. break;
  1843. default:
  1844. if (rgb == _clrBk)
  1845. hbr = _hbrBk;
  1846. else
  1847. hbr = hbrFree = CreateSolidBrush(rgb);
  1848. break;
  1849. }
  1850. hbrT = (HBRUSH)SelectObject(hdcDst, hbr);
  1851. PatBlt(hdcDst, xDst, yDst, cx, cy, PATCOPY);
  1852. SelectObject(hdcDst, hbrT);
  1853. hbrT = (HBRUSH)SelectObject(hdcDst, hbrMask);
  1854. BitBlt(hdcDst, xDst, yDst, cx, cy, _hdcImage, x, y, ROP_MaskPat);
  1855. SelectObject(hdcDst, hbrT);
  1856. if (hbrFree)
  1857. DeleteBrush(hbrFree);
  1858. }
  1859. /*
  1860. ** BlendCT
  1861. **
  1862. ** copy the source to the dest blended with the given color.
  1863. **
  1864. */
  1865. void CImageList::BlendCT(HDC hdcDst, int xDst, int yDst, int x, int y, int cx, int cy, COLORREF rgb, UINT fStyle)
  1866. {
  1867. BITMAP bm;
  1868. GetObject(_hbmImage, sizeof(bm), &bm);
  1869. if (rgb == CLR_DEFAULT)
  1870. rgb = GetSysColor(COLOR_HIGHLIGHT);
  1871. ASSERT(rgb != CLR_NONE);
  1872. //
  1873. // get the DIB color table and blend it, only do this when the
  1874. // blend color changes
  1875. //
  1876. if (_clrBlend != rgb)
  1877. {
  1878. int n,cnt;
  1879. _clrBlend = rgb;
  1880. GetObject(_hbmImage, sizeof(dib), &dib.bm);
  1881. cnt = GetDIBColorTable(_hdcImage, 0, 256, (LPRGBQUAD)&dib.ct);
  1882. if ((fStyle & ILD_BLENDMASK) == ILD_BLEND50)
  1883. n = 50;
  1884. else
  1885. n = 25;
  1886. BlendCTHelper(dib.ct, rgb, n, cnt);
  1887. }
  1888. //
  1889. // draw the image with a different color table
  1890. //
  1891. StretchDIBits(hdcDst, xDst, yDst, cx, cy,
  1892. x, dib.bi.biHeight-(y+cy), cx, cy,
  1893. bm.bmBits, (LPBITMAPINFO)&dib.bi, DIB_RGB_COLORS, SRCCOPY);
  1894. }
  1895. // RGB555 macros
  1896. #define RGB555(r,g,b) (((((r)>>3)&0x1F)<<10) | ((((g)>>3)&0x1F)<<5) | (((b)>>3)&0x1F))
  1897. #define R_555(w) (int)(((w) >> 7) & 0xF8)
  1898. #define G_555(w) (int)(((w) >> 2) & 0xF8)
  1899. #define B_555(w) (int)(((w) << 3) & 0xF8)
  1900. void CImageList::Blend16Helper(int xSrc, int ySrc, int xDst, int yDst, int cx, int cy, COLORREF rgb, int a) // alpha value
  1901. {
  1902. // If it's odd, Adjust.
  1903. if ((cx & 1) == 1)
  1904. {
  1905. cx++;
  1906. }
  1907. if (rgb == CLR_NONE)
  1908. {
  1909. // blending with the destination, we ignore the alpha and always
  1910. // do 50% (this is what the old dither mask code did)
  1911. int ys = ySrc;
  1912. int yd = yDst;
  1913. for (; ys < ySrc + cy; ys++, yd++)
  1914. {
  1915. WORD* pSrc = &((WORD*)_pargbImage)[xSrc + ys * cx]; // Cast because we've gotten to this case because we are a 555 imagelist
  1916. WORD* pDst = &((WORD*)_pargbImage)[xDst + yd * cx];
  1917. for (int x = 0; x < cx; x++)
  1918. {
  1919. *pDst++ = ((*pDst & 0x7BDE) >> 1) + ((*pSrc++ & 0x7BDE) >> 1);
  1920. }
  1921. }
  1922. }
  1923. else
  1924. {
  1925. // blending with a solid color
  1926. // pre multiply source (constant) rgb by alpha
  1927. int sr = GetRValue(rgb) * a;
  1928. int sg = GetGValue(rgb) * a;
  1929. int sb = GetBValue(rgb) * a;
  1930. // compute inverse alpha for inner loop
  1931. a = 256 - a;
  1932. // special case a 50% blend, to avoid a multiply
  1933. if (a == 128)
  1934. {
  1935. sr = RGB555(sr>>8,sg>>8,sb>>8);
  1936. int ys = ySrc;
  1937. int yd = yDst;
  1938. for (; ys < ySrc + cy; ys++, yd++)
  1939. {
  1940. WORD* pSrc = &((WORD*)_pargbImage)[xSrc + ys * cx];
  1941. WORD* pDst = &((WORD*)_pargbImage)[xDst + yd * cx];
  1942. for (int x = 0; x < cx; x++)
  1943. {
  1944. int i = *pSrc++;
  1945. i = sr + ((i & 0x7BDE) >> 1);
  1946. *pDst++ = (WORD) i;
  1947. }
  1948. }
  1949. }
  1950. else
  1951. {
  1952. int ys = ySrc;
  1953. int yd = yDst;
  1954. for (; ys < ySrc + cy; ys++, yd++)
  1955. {
  1956. WORD* pSrc = &((WORD*)_pargbImage)[xSrc + ys * cx];
  1957. WORD* pDst = &((WORD*)_pargbImage)[xDst + yd * cx];
  1958. for (int x = 0; x < cx; x++)
  1959. {
  1960. int i = *pSrc++;
  1961. int r = (R_555(i) * a + sr) >> 8;
  1962. int g = (G_555(i) * a + sg) >> 8;
  1963. int b = (B_555(i) * a + sb) >> 8;
  1964. *pDst++ = RGB555(r,g,b);
  1965. }
  1966. }
  1967. }
  1968. }
  1969. }
  1970. /*
  1971. ** ImageList_Blend16
  1972. **
  1973. ** copy the source to the dest blended with the given color.
  1974. **
  1975. ** source is assumed to be a 16 bit (RGB 555) bottom-up DIBSection
  1976. ** (this is the only kind of DIBSection we create)
  1977. */
  1978. void CImageList::Blend16(HDC hdcDst, int xDst, int yDst, int iImage, int cx, int cy, COLORREF rgb, UINT fStyle)
  1979. {
  1980. BITMAP bm;
  1981. RECT rc;
  1982. RECT rcSpare;
  1983. RECT rcSpareInverted;
  1984. int a, x, y;
  1985. // get bitmap info for source bitmap
  1986. GetObject(_hbmImage, sizeof(bm), &bm);
  1987. ASSERT(bm.bmBitsPixel==16);
  1988. // get blend RGB
  1989. if (rgb == CLR_DEFAULT)
  1990. rgb = GetSysColor(COLOR_HIGHLIGHT);
  1991. // get blend factor as a fraction of 256
  1992. // only 50% or 25% is currently used.
  1993. if ((fStyle & ILD_BLENDMASK) == ILD_BLEND50)
  1994. a = 128;
  1995. else
  1996. a = 64;
  1997. GetImageRectInverted(iImage, &rc);
  1998. x = rc.left;
  1999. y = rc.top;
  2000. // blend the image with the specified color and place at end of image list
  2001. if (GetSpareImageRectInverted(&rcSpareInverted) &&
  2002. GetSpareImageRect(&rcSpare))
  2003. {
  2004. // if blending with the destination, copy the dest to our work buffer
  2005. if (rgb == CLR_NONE)
  2006. BitBlt(_hdcImage, rcSpare.left, rcSpare.top, cx, cy, hdcDst, xDst, yDst, SRCCOPY);
  2007. // sometimes the user can change the icon size (via plustab) between 32x32 and 48x48,
  2008. // thus the values we have might be bigger than the actual bitmap. To prevent us from
  2009. // crashing in Blend16 when this happens we do some bounds checks here
  2010. if (rc.left + cx <= bm.bmWidth &&
  2011. rc.top + cy <= bm.bmHeight &&
  2012. x + cx <= bm.bmWidth &&
  2013. y + cy <= bm.bmHeight)
  2014. {
  2015. // Needs inverted coordinates
  2016. Blend16Helper(x, y, rcSpareInverted.left, rcSpareInverted.top, cx, cy, rgb, a);
  2017. }
  2018. // blt blended image to the dest DC
  2019. BitBlt(hdcDst, xDst, yDst, cx, cy, _hdcImage, rcSpare.left, rcSpare.top, SRCCOPY);
  2020. }
  2021. }
  2022. #define ALPHA_50 128
  2023. #define ALPHA_25 64
  2024. void CImageList::_GenerateAlphaForImageUsingMask(int iImage, BOOL fSpare)
  2025. {
  2026. RECT rcImage;
  2027. RECT rcInverted;
  2028. HRESULT hr;
  2029. GetImageRect(iImage, &rcImage);
  2030. if (fSpare)
  2031. {
  2032. hr = GetSpareImageRectInverted(&rcInverted);
  2033. }
  2034. else
  2035. {
  2036. hr = GetImageRectInverted(iImage, &rcInverted);
  2037. }
  2038. if (!SUCCEEDED(hr))
  2039. return;
  2040. BITMAPINFO bi = {0};
  2041. bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
  2042. bi.bmiHeader.biWidth = _cx;
  2043. bi.bmiHeader.biHeight = _cy;
  2044. bi.bmiHeader.biPlanes = 1;
  2045. bi.bmiHeader.biBitCount = 32;
  2046. bi.bmiHeader.biCompression = BI_RGB;
  2047. HDC hdcMem = CreateCompatibleDC(_hdcMask);
  2048. if (hdcMem)
  2049. {
  2050. RGBQUAD* pbMask;
  2051. HBITMAP hbmp = CreateDIBSection(hdcMem, &bi, DIB_RGB_COLORS, (void**)&pbMask, NULL, 0);
  2052. if (hbmp)
  2053. {
  2054. HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcMem, hbmp);
  2055. SetTextColor(hdcMem, RGB(0xFF, 0xFF, 0xFF));
  2056. ::SetBkColor(hdcMem, RGB(0x0,0x0,0x0));
  2057. BitBlt(hdcMem, 0, 0, _cx, _cy, _hdcMask, rcImage.left, rcImage.top, SRCCOPY);
  2058. for (int y = 0; y < _cy; y++)
  2059. {
  2060. int Offset = (y + rcInverted.top) * _cx;
  2061. int MaskOffset = y * _cx;
  2062. for (int x = 0; x < _cx; x++)
  2063. {
  2064. RGBQUAD* prgb = &_pargbImage[x + rcInverted.left + Offset];
  2065. if (pbMask[x + MaskOffset].rgbBlue != 0)
  2066. {
  2067. prgb->rgbReserved = 255;
  2068. }
  2069. else
  2070. {
  2071. *(DWORD*)prgb = 0;
  2072. }
  2073. }
  2074. }
  2075. SelectObject(hdcMem, hbmpOld);
  2076. DeleteObject(hbmp);
  2077. }
  2078. DeleteDC(hdcMem);
  2079. }
  2080. if (!fSpare)
  2081. {
  2082. SetItemFlags(iImage, ILIF_ALPHA);
  2083. _PreProcessImage(iImage);
  2084. }
  2085. }
  2086. void ScaleAlpha(RGBQUAD* prgbImage, RECT* prc, int aScale)
  2087. {
  2088. int cx = RECTWIDTH(*prc);
  2089. for (int y = prc->top; y < prc->bottom; y++)
  2090. {
  2091. int Offset = y * cx;
  2092. for (int x = prc->left; x < prc->right; x++)
  2093. {
  2094. RGBQUAD* prgb = &prgbImage[x + Offset];
  2095. if (prgb->rgbReserved != 0)
  2096. {
  2097. prgb->rgbReserved = (BYTE)(prgb->rgbReserved / aScale); // New alpha
  2098. prgb->rgbRed = ((prgb->rgbRed * prgb->rgbReserved) + 128) / 255;
  2099. prgb->rgbGreen = ((prgb->rgbGreen * prgb->rgbReserved) + 128) / 255;
  2100. prgb->rgbBlue = ((prgb->rgbBlue * prgb->rgbReserved) + 128) / 255;
  2101. }
  2102. }
  2103. }
  2104. }
  2105. #define COLORBLEND_ALPHA 128
  2106. BOOL CImageList::Blend32(HDC hdcDst, int xDst, int yDst, int iImage, int cx, int cy, COLORREF rgb, UINT fStyle)
  2107. {
  2108. BITMAP bm;
  2109. RECT rc;
  2110. RECT rcSpare;
  2111. RECT rcSpareInverted;
  2112. int aScale;
  2113. BOOL fBlendWithColor = FALSE;
  2114. int r,g,b;
  2115. // get bitmap info for source bitmap
  2116. GetObject(_hbmImage, sizeof(bm), &bm);
  2117. ASSERT(bm.bmBitsPixel==32);
  2118. // get blend RGB
  2119. if (rgb == CLR_DEFAULT)
  2120. {
  2121. rgb = GetSysColor(COLOR_HIGHLIGHT);
  2122. fBlendWithColor = TRUE;
  2123. r = GetRValue(rgb) * COLORBLEND_ALPHA;
  2124. g = GetGValue(rgb) * COLORBLEND_ALPHA;
  2125. b = GetBValue(rgb) * COLORBLEND_ALPHA;
  2126. }
  2127. // get blend factor as a fraction of 256
  2128. // only 50% or 25% is currently used.
  2129. if ((fStyle & ILD_BLENDMASK) == ILD_BLEND50 || rgb == CLR_NONE)
  2130. aScale = 2;
  2131. else
  2132. aScale = 4;
  2133. GetImageRect(iImage, &rc);
  2134. if (GetSpareImageRectInverted(&rcSpareInverted) &&
  2135. GetSpareImageRect(&rcSpare))
  2136. {
  2137. BitBlt(_hdcImage, rcSpare.left, rcSpare.top, _cx, _cy, _hdcImage, rc.left, rc.top, SRCCOPY);
  2138. BOOL fHasAlpha = (_GetItemFlags(iImage) & ILIF_ALPHA);
  2139. if (!fHasAlpha)
  2140. {
  2141. _GenerateAlphaForImageUsingMask(iImage, TRUE);
  2142. }
  2143. // if blending with the destination, copy the dest to our work buffer
  2144. if (rgb == CLR_NONE)
  2145. {
  2146. ScaleAlpha(_pargbImage, &rcSpareInverted, aScale);
  2147. BLENDFUNCTION bf = {0};
  2148. bf.BlendOp = AC_SRC_OVER;
  2149. bf.SourceConstantAlpha = 255;
  2150. bf.AlphaFormat = AC_SRC_ALPHA;
  2151. bf.BlendFlags = AC_MIRRORBITMAP | ((fStyle & ILD_DPISCALE)?AC_USE_HIGHQUALITYFILTER:0);
  2152. GdiAlphaBlend(hdcDst, xDst, yDst, cx, cy, _hdcImage, rcSpare.left, rcSpare.top, _cx, _cy, bf);
  2153. return FALSE;
  2154. }
  2155. else
  2156. {
  2157. if (fBlendWithColor)
  2158. {
  2159. for (int y = rcSpareInverted.top; y < rcSpareInverted.bottom; y++)
  2160. {
  2161. int Offset = y * _cx;
  2162. for (int x = rcSpareInverted.left; x < rcSpareInverted.right; x++)
  2163. {
  2164. RGBQUAD* prgb = &_pargbImage[x + Offset];
  2165. if (prgb->rgbReserved > 128)
  2166. {
  2167. prgb->rgbRed = (prgb->rgbRed * COLORBLEND_ALPHA + r) / 255;
  2168. prgb->rgbGreen = (prgb->rgbGreen * COLORBLEND_ALPHA + g) / 255;
  2169. prgb->rgbBlue = (prgb->rgbBlue * COLORBLEND_ALPHA + b) / 255;
  2170. }
  2171. }
  2172. }
  2173. }
  2174. else
  2175. {
  2176. ScaleAlpha(_pargbImage, &rcSpareInverted, aScale);
  2177. }
  2178. BitBlt(hdcDst, xDst, yDst, cx, cy, _hdcImage, rcSpare.left, rcSpare.top, SRCCOPY);
  2179. return TRUE;
  2180. }
  2181. }
  2182. return FALSE;
  2183. }
  2184. /*
  2185. ** ImageList_Blend
  2186. **
  2187. ** copy the source to the dest blended with the given color.
  2188. ** top level function to decide what blend function to call
  2189. */
  2190. BOOL CImageList::Blend(HDC hdcDst, int xDst, int yDst, int iImage, int cx, int cy, COLORREF rgb, UINT fStyle)
  2191. {
  2192. BOOL fRet = FALSE;
  2193. BITMAP bm;
  2194. RECT rc;
  2195. int bpp = GetDeviceCaps(hdcDst, BITSPIXEL);
  2196. GetObject(_hbmImage, sizeof(bm), &bm);
  2197. GetImageRect(iImage, &rc);
  2198. //
  2199. // if _hbmImage is a DIBSection and we are on a HiColor device
  2200. // the do a "real" blend
  2201. //
  2202. if (bm.bmBits && bm.bmBitsPixel <= 8 && (bpp > 8 || bm.bmBitsPixel==8))
  2203. {
  2204. // blend from a 4bit or 8bit DIB
  2205. BlendCT(hdcDst, xDst, yDst, rc.left, rc.top, cx, cy, rgb, fStyle);
  2206. }
  2207. else if (bm.bmBits && bm.bmBitsPixel == 16 && bpp > 8)
  2208. {
  2209. // blend from a 16bit 555 DIB
  2210. Blend16(hdcDst, xDst, yDst, iImage, cx, cy, rgb, fStyle);
  2211. }
  2212. else if ((_flags & ILC_COLORMASK) == ILC_COLOR32)
  2213. {
  2214. fRet = Blend32(hdcDst, xDst, yDst, iImage, cx, cy, rgb, fStyle);
  2215. }
  2216. else
  2217. {
  2218. // simulate a blend with a dither pattern.
  2219. BlendDither(hdcDst, xDst, yDst, rc.left, rc.top, cx, cy, rgb, fStyle);
  2220. }
  2221. return fRet;
  2222. }
  2223. #define RGB_to_Gray(x) ((54 * GetRValue((x)) + 183 * GetGValue((x)) + 19 * GetBValue((x))) >> 8)
  2224. void TrueSaturateBits(void* pvBitmapBits, int Amount, int cx, int cy)
  2225. {
  2226. ULONG* pulSrc = (ULONG*)pvBitmapBits;
  2227. if ((cx > 0) && (cy > 0) && pulSrc)
  2228. {
  2229. for (int i = cx*cy - 1; i >= 0; i--)
  2230. {
  2231. /*
  2232. Enable this if you need true saturation adjustment
  2233. justmann 25-JAN-2001
  2234. ULONG ulR = GetRValue(*pulSrc);
  2235. ULONG ulG = GetGValue(*pulSrc);
  2236. ULONG ulB = GetBValue(*pulSrc);
  2237. ulGray = (54 * ulR + 183 * ulG + 19 * ulB) >> 8;
  2238. ULONG ulTemp = ulGray * (0xff - Amount);
  2239. ulR = (ulR * Amount + ulTemp) >> 8;
  2240. ulG = (ulG * Amount + ulTemp) >> 8;
  2241. ulB = (ulB * Amount + ulTemp) >> 8;
  2242. *pulSrc = (*pulSrc & 0xff000000) | RGB(R, G, B);
  2243. */
  2244. ULONG ulGray = RGB_to_Gray(*pulSrc);
  2245. *pulSrc = (*pulSrc & 0xff000000) | RGB(ulGray, ulGray, ulGray);
  2246. pulSrc++;
  2247. }
  2248. }
  2249. else
  2250. {
  2251. // This should never happen, if it does somebody has a bogus DIB section or does not
  2252. // understand what width or height is!
  2253. ASSERT(0);
  2254. }
  2255. }
  2256. BOOL CImageList::_MaskStretchBlt(BOOL fStretch, int i, HDC hdcDst, int xDst, int yDst, int cxDst, int cyDst,
  2257. HDC hdcImage, int xSrc, int ySrc, int cxSrc, int cySrc,
  2258. int xMask, int yMask,
  2259. DWORD dwRop)
  2260. {
  2261. BOOL fRet = TRUE;
  2262. if (fStretch == FALSE)
  2263. {
  2264. fRet = MaskBlt(hdcDst, xDst, yDst, cxDst, cyDst, hdcImage,
  2265. xSrc, ySrc, _hbmMask, xMask, yMask, dwRop);
  2266. }
  2267. else
  2268. {
  2269. //
  2270. // we have some special cases:
  2271. //
  2272. // if the background color is black, we just do a AND then OR
  2273. // if the background color is white, we just do a OR then AND
  2274. // otherwise change source, then AND then OR
  2275. //
  2276. COLORREF clrTextSave = SetTextColor(hdcDst, CLR_BLACK);
  2277. COLORREF clrBkSave = ::SetBkColor(hdcDst, CLR_WHITE);
  2278. // we cant do white/black special cases if we munged the mask or image
  2279. if (i != -1 && _clrBk == CLR_WHITE)
  2280. {
  2281. StretchBlt(hdcDst, xDst, yDst, cxDst, cyDst, _hdcMask, xMask, yMask, cxSrc, cySrc, ROP_DSno);
  2282. StretchBlt(hdcDst, xDst, yDst, cxDst, cyDst, hdcImage, xSrc, ySrc, cxSrc, cySrc, ROP_DSa);
  2283. }
  2284. else if (i != -1 && (_clrBk == CLR_BLACK || _clrBk == CLR_NONE))
  2285. {
  2286. StretchBlt(hdcDst, xDst, yDst, cxDst, cyDst, _hdcMask, xMask, yMask, cxSrc, cySrc, ROP_DSa);
  2287. StretchBlt(hdcDst, xDst, yDst, cxDst, cyDst, hdcImage, xSrc, ySrc, cxSrc, cySrc, ROP_DSo);
  2288. }
  2289. else
  2290. {
  2291. // black out the source image.
  2292. BitBlt(hdcImage, xSrc, ySrc, cxSrc, cySrc, _hdcMask, xMask, yMask, ROP_DSna);
  2293. StretchBlt(hdcDst, xDst, yDst, cxDst, cyDst, _hdcMask, xMask, yMask, cxSrc, cySrc, ROP_DSa);
  2294. StretchBlt(hdcDst, xDst, yDst, cxDst, cyDst, hdcImage, xSrc, ySrc, cxSrc, cySrc, ROP_DSo);
  2295. if (i != -1)
  2296. _ResetBkColor(i, i, _clrBk);
  2297. }
  2298. SetTextColor(hdcDst, clrTextSave);
  2299. ::SetBkColor(hdcDst, clrBkSave);
  2300. }
  2301. return fRet;
  2302. }
  2303. BOOL CImageList::_StretchBlt(BOOL fStretch, HDC hdc, int x, int y, int cx, int cy,
  2304. HDC hdcSrc, int xs, int ys, int cxs, int cys, DWORD dwRop)
  2305. {
  2306. if (fStretch)
  2307. return StretchBlt(hdc, x, y, cx, cy,
  2308. hdcSrc, xs, ys, cxs, cys, dwRop);
  2309. return BitBlt(hdc, x, y, cx, cy, hdcSrc, xs, ys, dwRop);
  2310. }
  2311. HRESULT CImageList::Draw(IMAGELISTDRAWPARAMS* pimldp)
  2312. {
  2313. RECT rcImage;
  2314. RECT rc;
  2315. HBRUSH hbrT;
  2316. BOOL fImage;
  2317. HDC hdcMaskI;
  2318. HDC hdcImageI;
  2319. int xMask, yMask;
  2320. int xImage, yImage;
  2321. int cxSource, cySource;
  2322. DWORD dwOldStretchBltMode;
  2323. BOOL fStretch;
  2324. BOOL fDPIScale = FALSE;
  2325. IMAGELISTDRAWPARAMS imldp = {0};
  2326. if (pimldp->cbSize != sizeof(IMAGELISTDRAWPARAMS))
  2327. {
  2328. if (pimldp->cbSize == IMAGELISTDRAWPARAMS_V3_SIZE)
  2329. {
  2330. memcpy(&imldp, pimldp, IMAGELISTDRAWPARAMS_V3_SIZE);
  2331. imldp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
  2332. pimldp = &imldp;
  2333. }
  2334. else
  2335. return E_INVALIDARG;
  2336. }
  2337. if (!IsImageListIndex(pimldp->i))
  2338. return E_INVALIDARG;
  2339. //
  2340. // If we need to use the mirrored imagelist, then let's set it.
  2341. //
  2342. if (_pimlMirror &&
  2343. (IS_DC_RTL_MIRRORED(pimldp->hdcDst)))
  2344. {
  2345. return _pimlMirror->Draw(pimldp);
  2346. }
  2347. ENTERCRITICAL;
  2348. dwOldStretchBltMode = SetStretchBltMode(pimldp->hdcDst, COLORONCOLOR);
  2349. GetImageRect(pimldp->i, &rcImage);
  2350. rcImage.left += pimldp->xBitmap;
  2351. rcImage.top += pimldp->yBitmap;
  2352. if (pimldp->rgbBk == CLR_DEFAULT)
  2353. pimldp->rgbBk = _clrBk;
  2354. if (pimldp->rgbBk == CLR_NONE)
  2355. pimldp->fStyle |= ILD_TRANSPARENT;
  2356. if (pimldp->cx == 0)
  2357. pimldp->cx = RECTWIDTH(rcImage);
  2358. if (pimldp->cy == 0)
  2359. pimldp->cy = RECTHEIGHT(rcImage);
  2360. BOOL fImageHasAlpha = (_GetItemFlags(pimldp->i) & ILIF_ALPHA);
  2361. again:
  2362. cxSource = RECTWIDTH(rcImage);
  2363. cySource = RECTHEIGHT(rcImage);
  2364. if (pimldp->cx <= 0 || pimldp->cy <= 0)
  2365. {
  2366. // caller asked to draw no (or negative) pixels; that's easy!
  2367. // Early-out this case so other parts of the drawing
  2368. // don't get confused.
  2369. goto exit;
  2370. }
  2371. if (pimldp->fStyle & ILD_DPISCALE)
  2372. {
  2373. CCDPIScaleX(&pimldp->cx);
  2374. CCDPIScaleY(&pimldp->cy);
  2375. fDPIScale = TRUE;
  2376. }
  2377. fStretch = (pimldp->fStyle & ILD_SCALE) || (fDPIScale);
  2378. if (fStretch)
  2379. {
  2380. dwOldStretchBltMode = SetStretchBltMode(pimldp->hdcDst, HALFTONE);
  2381. }
  2382. hdcMaskI = _hdcMask;
  2383. xMask = rcImage.left;
  2384. yMask = rcImage.top;
  2385. hdcImageI = _hdcImage;
  2386. xImage = rcImage.left;
  2387. yImage = rcImage.top;
  2388. if (pimldp->fStyle & ILD_BLENDMASK)
  2389. {
  2390. // make a copy of the image, because we will have to modify it
  2391. HDC hdcT = ImageList_GetWorkDC(pimldp->hdcDst, (_flags & ILC_COLORMASK) == ILC_COLOR32, pimldp->cx, pimldp->cy);
  2392. if (hdcT)
  2393. {
  2394. hdcImageI = hdcT;
  2395. xImage = 0;
  2396. yImage = 0;
  2397. //
  2398. // blend with the destination
  2399. // by "oring" the mask with a 50% dither mask
  2400. //
  2401. if (pimldp->rgbFg == CLR_NONE && hdcMaskI)
  2402. {
  2403. fImageHasAlpha = FALSE;
  2404. if ((_flags & ILC_COLORMASK) == ILC_COLOR32 &&
  2405. !(pimldp->fStyle & ILD_MASK))
  2406. {
  2407. // copy dest to our work buffer
  2408. _StretchBlt(fStretch, hdcImageI, 0, 0, pimldp->cx, pimldp->cy, pimldp->hdcDst, pimldp->x, pimldp->y, cxSource, cySource, SRCCOPY);
  2409. Blend32(hdcImageI, 0, 0, pimldp->i, pimldp->cx, pimldp->cy, pimldp->rgbFg, pimldp->fStyle);
  2410. }
  2411. else if ((_flags & ILC_COLORMASK) == ILC_COLOR16 &&
  2412. !(pimldp->fStyle & ILD_MASK))
  2413. {
  2414. // copy dest to our work buffer
  2415. _StretchBlt(fStretch, hdcImageI, 0, 0, pimldp->cx, pimldp->cy, pimldp->hdcDst, pimldp->x, pimldp->y, cxSource, cySource, SRCCOPY);
  2416. // blend source into our work buffer
  2417. Blend16(hdcImageI, 0, 0, pimldp->i, pimldp->cx, pimldp->cy, pimldp->rgbFg, pimldp->fStyle);
  2418. pimldp->fStyle |= ILD_TRANSPARENT;
  2419. }
  2420. else
  2421. {
  2422. GetSpareImageRect(&rc);
  2423. xMask = rc.left;
  2424. yMask = rc.top;
  2425. // copy the source image
  2426. _StretchBlt(fStretch, hdcImageI, 0, 0, pimldp->cx, pimldp->cy,
  2427. _hdcImage, rcImage.left, rcImage.top, cxSource, cySource, SRCCOPY);
  2428. // make a dithered copy of the mask
  2429. hbrT = (HBRUSH)SelectObject(hdcMaskI, g_hbrMonoDither);
  2430. _StretchBlt(fStretch, hdcMaskI, rc.left, rc.top, pimldp->cx, pimldp->cy,
  2431. _hdcMask, rcImage.left, rcImage.top, cxSource, cySource, ROP_PSo);
  2432. SelectObject(hdcMaskI, hbrT);
  2433. pimldp->fStyle |= ILD_TRANSPARENT;
  2434. }
  2435. }
  2436. else
  2437. {
  2438. // blend source into our work buffer
  2439. if (Blend(hdcImageI, 0, 0, pimldp->i, pimldp->cx, pimldp->cy, pimldp->rgbFg, pimldp->fStyle))
  2440. {
  2441. fImageHasAlpha = (_flags & ILC_COLORMASK) == ILC_COLOR32;
  2442. }
  2443. }
  2444. }
  2445. }
  2446. // is the source image from the image list (not hdcWork)
  2447. fImage = hdcImageI == _hdcImage;
  2448. if (pimldp->cbSize >= sizeof(IMAGELISTDRAWPARAMS) &&
  2449. pimldp->fState & ILS_GLOW ||
  2450. pimldp->fState & ILS_SHADOW ||
  2451. pimldp->fState & ILS_SATURATE ||
  2452. pimldp->fState & ILS_ALPHA)
  2453. {
  2454. int z;
  2455. ULONG* pvBits;
  2456. HDC hdcMem = CreateCompatibleDC(pimldp->hdcDst);
  2457. HBITMAP hbmpOld;
  2458. HBITMAP hbmp;
  2459. BITMAPINFO bi = {0};
  2460. BLENDFUNCTION bf = {0};
  2461. DWORD dwAlphaAmount = 0x000000ff;
  2462. COLORREF crAlphaColor = pimldp->crEffect; // Need to make this a selectable color
  2463. int x, y;
  2464. int xOffset, yOffset;
  2465. SIZE size = {cxSource, cySource};
  2466. if (hdcMem)
  2467. {
  2468. if (pimldp->fState & ILS_SHADOW)
  2469. {
  2470. x = 5; // This is a "Blur fudge Factor"
  2471. y = 5; //
  2472. xOffset = -(DROP_SHADOW - x);
  2473. yOffset = -(DROP_SHADOW - y);
  2474. size.cx = pimldp->cx + 10;
  2475. size.cy = pimldp->cy + 10;
  2476. dwAlphaAmount = 0x00000050;
  2477. crAlphaColor = RGB(0, 0, 0);
  2478. }
  2479. else if (pimldp->fState & ILS_GLOW)
  2480. {
  2481. xOffset = x = 10;
  2482. yOffset = y = 10;
  2483. size.cx = pimldp->cx + (GLOW_RADIUS * 2);
  2484. size.cy = pimldp->cy + (GLOW_RADIUS * 2);
  2485. }
  2486. else if (pimldp->fState & ILS_ALPHA)
  2487. {
  2488. xOffset = x = 0;
  2489. yOffset = y = 0;
  2490. size.cx = pimldp->cx;
  2491. size.cy = pimldp->cy;
  2492. }
  2493. bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
  2494. bi.bmiHeader.biWidth = size.cx;
  2495. bi.bmiHeader.biHeight = size.cy;
  2496. bi.bmiHeader.biPlanes = 1;
  2497. bi.bmiHeader.biBitCount = 32;
  2498. bi.bmiHeader.biCompression = BI_RGB;
  2499. hbmp = CreateDIBSection(hdcMem, &bi, DIB_RGB_COLORS, (VOID**)&pvBits, NULL, 0);
  2500. if (hbmp)
  2501. {
  2502. hbmpOld = (HBITMAP)SelectObject(hdcMem, hbmp);
  2503. ZeroMemory(pvBits, size.cx * size.cy);
  2504. if (pimldp->fState & ILS_SHADOW || pimldp->fState & ILS_GLOW || pimldp->fState & ILS_ALPHA)
  2505. {
  2506. if (_hbmMask)
  2507. {
  2508. MaskBlt(hdcMem, pimldp->x, pimldp->y, size.cx, size.cy,
  2509. hdcImageI, xImage, yImage, _hbmMask, xMask, yMask, 0xCCAA0000);
  2510. }
  2511. else if (pimldp->fState & ILS_SHADOW)
  2512. {
  2513. RECT rc = {x, y, size.cx, size.cy};
  2514. FillRectClr(hdcMem, &rc, RGB(0x0F, 0x0F, 0x0F)); // White so that it gets inverted into a shadow
  2515. }
  2516. else
  2517. {
  2518. BitBlt(hdcMem, x, y, size.cx, size.cy, hdcImageI, xImage, yImage, SRCCOPY);
  2519. }
  2520. int iTotalSize = size.cx * size.cy;
  2521. if (pimldp->fState & ILS_ALPHA)
  2522. {
  2523. for (z = 0; z < iTotalSize; z++)
  2524. {
  2525. RGBQUAD* prgb = &((RGBQUAD*)pvBits)[z];
  2526. prgb->rgbReserved = (BYTE)(pimldp->Frame & 0xFF);
  2527. prgb->rgbRed = ((prgb->rgbRed * prgb->rgbReserved) + 128) / 255;
  2528. prgb->rgbGreen = ((prgb->rgbGreen * prgb->rgbReserved) + 128) / 255;
  2529. prgb->rgbBlue = ((prgb->rgbBlue * prgb->rgbReserved) + 128) / 255;
  2530. }
  2531. }
  2532. else
  2533. {
  2534. for (z = 0; z < iTotalSize; z++)
  2535. {
  2536. if (((PULONG)pvBits)[z] != 0)
  2537. ((PULONG)pvBits)[z] = dwAlphaAmount;
  2538. }
  2539. BlurBitmap(pvBits, size.cx, size.cy, crAlphaColor);
  2540. if (!(pimldp->fState & ILS_SHADOW))
  2541. {
  2542. for (z = 0; z < iTotalSize; z++)
  2543. {
  2544. if (((PULONG)pvBits)[z] > 0x09000000)
  2545. ((PULONG)pvBits)[z] = dwAlphaAmount;
  2546. }
  2547. BlurBitmap(pvBits, size.cx, size.cy, crAlphaColor);
  2548. BlurBitmap(pvBits, size.cx, size.cy, crAlphaColor);
  2549. }
  2550. }
  2551. bf.BlendOp = AC_SRC_OVER;
  2552. bf.SourceConstantAlpha = 255;
  2553. bf.AlphaFormat = AC_SRC_ALPHA;
  2554. bf.BlendFlags = fDPIScale?AC_USE_HIGHQUALITYFILTER:0;
  2555. // Do not mirror the bitmap. By this point it is correctly mirrored
  2556. GdiAlphaBlend(pimldp->hdcDst, pimldp->x - xOffset, pimldp->y - yOffset, pimldp->cx, pimldp->cy,
  2557. hdcMem, 0, 0, size.cx, size.cy, bf);
  2558. }
  2559. else
  2560. {
  2561. BitBlt(hdcMem, 0, 0, pimldp->cx, pimldp->cy, hdcImageI, xImage, yImage, SRCCOPY);
  2562. TrueSaturateBits(pvBits, pimldp->Frame, size.cx, size.cy);
  2563. if (fImageHasAlpha)
  2564. {
  2565. bf.BlendOp = AC_SRC_OVER;
  2566. bf.SourceConstantAlpha = 150;
  2567. bf.AlphaFormat = AC_SRC_ALPHA;
  2568. // Do not mirror the bitmap. By this point it is correctly mirrored
  2569. GdiAlphaBlend(pimldp->hdcDst, pimldp->x, pimldp->y, pimldp->cx, pimldp->cy, hdcMem, 0, 0, cxSource, cySource, bf);
  2570. }
  2571. else if (_hbmMask)
  2572. {
  2573. _MaskStretchBlt(fStretch, -1, hdcMem, pimldp->x, pimldp->y, pimldp->cx, pimldp->cy,
  2574. hdcMem, 0, 0, cxSource, cySource, xMask, yMask, 0xCCAA0000);
  2575. }
  2576. else
  2577. {
  2578. _StretchBlt(fStretch, pimldp->hdcDst, pimldp->x, pimldp->y, pimldp->cx, pimldp->cy, hdcMem, 0, 0, cxSource,cySource, SRCCOPY);
  2579. }
  2580. }
  2581. SelectObject(hdcMem, hbmpOld);
  2582. DeleteObject(hbmp);
  2583. pimldp->fStyle |= ILD_TRANSPARENT;
  2584. }
  2585. DeleteDC(hdcMem);
  2586. }
  2587. if (pimldp->fState & ILS_SHADOW || pimldp->fState & ILS_GLOW)
  2588. {
  2589. if (pimldp->fState & ILS_SHADOW)
  2590. {
  2591. pimldp->fState &= ~ILS_SHADOW;
  2592. //pimldp->x -= DROP_SHADOW;
  2593. //pimldp->y -= DROP_SHADOW;
  2594. }
  2595. else
  2596. {
  2597. pimldp->fState &= ~ILS_GLOW;
  2598. }
  2599. goto again;
  2600. }
  2601. }
  2602. else if ((pimldp->fStyle & ILD_MASK) && hdcMaskI)
  2603. {
  2604. //
  2605. // ILD_MASK means draw the mask only
  2606. //
  2607. DWORD dwRop;
  2608. ASSERT(GetTextColor(pimldp->hdcDst) == CLR_BLACK);
  2609. ASSERT(::GetBkColor(pimldp->hdcDst) == CLR_WHITE);
  2610. if (pimldp->fStyle & ILD_ROP)
  2611. dwRop = pimldp->dwRop;
  2612. else if (pimldp->fStyle & ILD_TRANSPARENT)
  2613. dwRop = SRCAND;
  2614. else
  2615. dwRop = SRCCOPY;
  2616. _StretchBlt(fStretch, pimldp->hdcDst, pimldp->x, pimldp->y, pimldp->cx, pimldp->cy, hdcMaskI, xMask, yMask, cxSource, cySource, dwRop);
  2617. }
  2618. else if (fImageHasAlpha && // this image has alpha
  2619. !(pimldp->fStyle & ILD_PRESERVEALPHA)) // But not if we're trying to preserve it.
  2620. {
  2621. if (!(pimldp->fStyle & ILD_TRANSPARENT))
  2622. {
  2623. COLORREF clr = pimldp->rgbBk;
  2624. if (clr == CLR_DEFAULT)
  2625. clr = _clrBk;
  2626. RECT rc = {pimldp->x, pimldp->y, pimldp->x + pimldp->cx, pimldp->y + pimldp->cy};
  2627. FillRectClr(pimldp->hdcDst, &rc, clr);
  2628. }
  2629. BLENDFUNCTION bf = {0};
  2630. bf.BlendOp = AC_SRC_OVER;
  2631. bf.SourceConstantAlpha = 255;
  2632. bf.AlphaFormat = AC_SRC_ALPHA;
  2633. bf.BlendFlags = AC_MIRRORBITMAP | (fDPIScale?AC_USE_HIGHQUALITYFILTER:0);
  2634. GdiAlphaBlend(pimldp->hdcDst, pimldp->x, pimldp->y, pimldp->cx, pimldp->cy, hdcImageI, xImage, yImage, cxSource, cySource, bf);
  2635. }
  2636. else if (pimldp->fStyle & ILD_IMAGE)
  2637. {
  2638. COLORREF clrBk = ::GetBkColor(hdcImageI);
  2639. DWORD dwRop;
  2640. if (pimldp->rgbBk != CLR_DEFAULT)
  2641. {
  2642. ::SetBkColor(hdcImageI, pimldp->rgbBk);
  2643. }
  2644. if (pimldp->fStyle & ILD_ROP)
  2645. dwRop = pimldp->dwRop;
  2646. else
  2647. dwRop = SRCCOPY;
  2648. _StretchBlt(fStretch, pimldp->hdcDst, pimldp->x, pimldp->y, pimldp->cx, pimldp->cy, hdcImageI, xImage, yImage, cxSource, cySource, dwRop);
  2649. ::SetBkColor(hdcImageI, clrBk);
  2650. }
  2651. else if ((pimldp->fStyle & ILD_TRANSPARENT) && hdcMaskI)
  2652. {
  2653. _MaskStretchBlt(fStretch, fImage?pimldp->i:-1,pimldp->hdcDst, pimldp->x, pimldp->y, pimldp->cx, pimldp->cy,
  2654. hdcImageI, xImage, yImage, cxSource, cySource, xMask, yMask, 0xCCAA0000);
  2655. }
  2656. else if (fImage && pimldp->rgbBk == _clrBk && _fSolidBk)
  2657. {
  2658. _StretchBlt(fStretch, pimldp->hdcDst, pimldp->x, pimldp->y, pimldp->cx, pimldp->cy, hdcImageI, xImage, yImage, cxSource, cySource, SRCCOPY);
  2659. }
  2660. else if (hdcMaskI && !fImageHasAlpha)
  2661. {
  2662. if (fImage &&
  2663. ((pimldp->rgbBk == _clrBk &&
  2664. !_fSolidBk) ||
  2665. GetNearestColor32(hdcImageI, pimldp->rgbBk) != pimldp->rgbBk))
  2666. {
  2667. // make a copy of the image, because we will have to modify it
  2668. hdcImageI = ImageList_GetWorkDC(pimldp->hdcDst, (_flags & ILC_COLORMASK) == ILC_COLOR32, pimldp->cx, pimldp->cy);
  2669. xImage = 0;
  2670. yImage = 0;
  2671. fImage = FALSE;
  2672. BitBlt(hdcImageI, 0, 0, pimldp->cx, pimldp->cy, _hdcImage, rcImage.left, rcImage.top, SRCCOPY);
  2673. }
  2674. SetBrushOrgEx(hdcImageI, xImage-pimldp->x, yImage-pimldp->y, NULL);
  2675. hbrT = SelectBrush(hdcImageI, CreateSolidBrush(pimldp->rgbBk));
  2676. BitBlt(hdcImageI, xImage, yImage, pimldp->cx, pimldp->cy, hdcMaskI, xMask, yMask, ROP_PatMask);
  2677. DeleteObject(SelectBrush(hdcImageI, hbrT));
  2678. SetBrushOrgEx(hdcImageI, 0, 0, NULL);
  2679. _StretchBlt(fStretch, pimldp->hdcDst, pimldp->x, pimldp->y, pimldp->cx, pimldp->cy, hdcImageI, xImage, yImage, cxSource, cySource, SRCCOPY);
  2680. if (fImage)
  2681. _ResetBkColor(pimldp->i, pimldp->i, _clrBk);
  2682. }
  2683. else
  2684. {
  2685. _StretchBlt(fStretch, pimldp->hdcDst, pimldp->x, pimldp->y, pimldp->cx, pimldp->cy, hdcImageI, xImage, yImage, cxSource, cySource, SRCCOPY);
  2686. }
  2687. //
  2688. // now deal with a overlay image, use the minimal bounding rect (and flags)
  2689. // we computed in ImageList_SetOverlayImage()
  2690. //
  2691. if (pimldp->fStyle & ILD_OVERLAYMASK)
  2692. {
  2693. int n = OVERLAYMASKTOINDEX(pimldp->fStyle);
  2694. if (n < NUM_OVERLAY_IMAGES)
  2695. {
  2696. pimldp->i = _aOverlayIndexes[n];
  2697. if (!fImageHasAlpha)
  2698. pimldp->fStyle &= ~ILD_PRESERVEALPHA;
  2699. if (pimldp->fStyle & ILD_PRESERVEALPHA &&
  2700. !(_GetItemFlags(pimldp->i) & ILIF_ALPHA))
  2701. {
  2702. _GenerateAlphaForImageUsingMask(pimldp->i, FALSE);
  2703. }
  2704. fImageHasAlpha = (_GetItemFlags(pimldp->i) & ILIF_ALPHA);
  2705. GetImageRect(pimldp->i, &rcImage);
  2706. int xOverlay = _aOverlayX[n];
  2707. int yOverlay = _aOverlayY[n];
  2708. int cxOverlay = _aOverlayDX[n];
  2709. int cyOverlay = _aOverlayDY[n];
  2710. if (fDPIScale)
  2711. {
  2712. CCDPIScaleX(&xOverlay );
  2713. CCDPIScaleY(&yOverlay );
  2714. }
  2715. pimldp->cx = cxOverlay;
  2716. pimldp->cy = cyOverlay;
  2717. pimldp->x += xOverlay;
  2718. pimldp->y += yOverlay;
  2719. rcImage.left += _aOverlayX[n] + pimldp->xBitmap;
  2720. rcImage.top += _aOverlayY[n] + pimldp->yBitmap;
  2721. rcImage.right = rcImage.left + _aOverlayDX[n];
  2722. rcImage.bottom = rcImage.top + _aOverlayDY[n];
  2723. pimldp->fStyle &= ILD_MASK;
  2724. pimldp->fStyle |= ILD_TRANSPARENT;
  2725. pimldp->fStyle |= (fDPIScale?ILD_DPISCALE:0);
  2726. pimldp->fStyle |= _aOverlayF[n];
  2727. if (fImageHasAlpha)
  2728. pimldp->fStyle &= ~(ILD_IMAGE);
  2729. if (pimldp->cx > 0 && pimldp->cy > 0)
  2730. goto again;
  2731. }
  2732. }
  2733. if (!fImage)
  2734. {
  2735. ImageList_ReleaseWorkDC(hdcImageI);
  2736. }
  2737. exit:
  2738. SetStretchBltMode(pimldp->hdcDst, dwOldStretchBltMode);
  2739. LEAVECRITICAL;
  2740. return S_OK;
  2741. }
  2742. HRESULT CImageList::GetImageInfo(int i, IMAGEINFO * pImageInfo)
  2743. {
  2744. RIPMSG(pImageInfo != NULL, "ImageList_GetImageInfo: Invalid NULL pointer");
  2745. RIPMSG(IsImageListIndex(i), "ImageList_GetImageInfo: Invalid image index %d", i);
  2746. if (!pImageInfo || !IsImageListIndex(i))
  2747. return E_POINTER;
  2748. pImageInfo->hbmImage = _hbmImage;
  2749. pImageInfo->hbmMask = _hbmMask;
  2750. return GetImageRect(i, &pImageInfo->rcImage);
  2751. }
  2752. //
  2753. // Parameter:
  2754. // i -- -1 to add
  2755. //
  2756. HRESULT CImageList::_ReplaceIcon(int i, HICON hIcon, int* pi)
  2757. {
  2758. HICON hIconT = hIcon;
  2759. RECT rc;
  2760. HRESULT hr = S_OK;
  2761. TraceMsg(TF_IMAGELIST, "ImageList_ReplaceIcon");
  2762. *pi = -1;
  2763. // be win95 compatible
  2764. if (i < -1)
  2765. return E_INVALIDARG;
  2766. //
  2767. // re-size the icon (iff needed) by calling CopyImage
  2768. //
  2769. hIcon = (HICON)CopyImage(hIconT, IMAGE_ICON, _cx, _cy, LR_COPYFROMRESOURCE | LR_COPYRETURNORG);
  2770. if (hIcon == NULL)
  2771. return E_OUTOFMEMORY;
  2772. //
  2773. // alocate a slot for the icon
  2774. //
  2775. if (i == -1)
  2776. hr = _Add(NULL,NULL,1,0,0,&i);
  2777. if (i == -1)
  2778. goto exit;
  2779. ENTERCRITICAL;
  2780. //
  2781. // now draw it into the image bitmaps
  2782. //
  2783. hr = GetImageRect(i, &rc);
  2784. if (FAILED(hr))
  2785. goto LeaveCritical;
  2786. if ((_flags & ILC_COLORMASK) == ILC_COLOR32)
  2787. {
  2788. BOOL fSuccess = FALSE;
  2789. ICONINFO io;
  2790. if (GetIconInfo(hIcon, &io))
  2791. {
  2792. BITMAP bm;
  2793. if (GetObject(io.hbmColor, sizeof(bm), &bm))
  2794. {
  2795. if (bm.bmBitsPixel == 32)
  2796. {
  2797. HDC h = CreateCompatibleDC(_hdcImage);
  2798. if (h)
  2799. {
  2800. HBITMAP hbmpOld = (HBITMAP)SelectObject(h, io.hbmColor);
  2801. BitBlt(_hdcImage, rc.left, rc.top, RECTWIDTH(rc), RECTHEIGHT(rc), h, 0, 0, SRCCOPY);
  2802. if (_HasAlpha(i))
  2803. {
  2804. SetItemFlags(i, ILIF_ALPHA);
  2805. _PreProcessImage(i);
  2806. fSuccess = TRUE;
  2807. }
  2808. SelectObject(h, hbmpOld);
  2809. DeleteDC(h);
  2810. }
  2811. }
  2812. }
  2813. DeleteObject(io.hbmColor);
  2814. DeleteObject(io.hbmMask);
  2815. }
  2816. if (!fSuccess)
  2817. {
  2818. // If it doesn't have alpha or we can't get info
  2819. SetItemFlags(i, 0);
  2820. }
  2821. }
  2822. if (_GetItemFlags(i) == 0)
  2823. {
  2824. FillRect(_hdcImage, &rc, _hbrBk);
  2825. DrawIconEx(_hdcImage, rc.left, rc.top, hIcon, 0, 0, 0, NULL, DI_NORMAL);
  2826. }
  2827. if (_hdcMask)
  2828. DrawIconEx(_hdcMask, rc.left, rc.top, hIcon, 0, 0, 0, NULL, DI_MASK);
  2829. hr = S_OK;
  2830. *pi = i;
  2831. LeaveCritical:
  2832. LEAVECRITICAL;
  2833. exit:
  2834. //
  2835. // if we had user size a new icon, delete it.
  2836. //
  2837. if (hIcon != hIconT)
  2838. DestroyIcon(hIcon);
  2839. return hr;
  2840. }
  2841. HRESULT CImageList::ReplaceIcon(int i, HICON hIcon, int* pi)
  2842. {
  2843. // Let's add it first to the mirrored image list, if one exists
  2844. if (_pimlMirror)
  2845. {
  2846. HICON hIconT = CopyIcon(hIcon);
  2847. if (hIconT)
  2848. {
  2849. MirrorIcon(&hIconT, NULL);
  2850. _pimlMirror->_ReplaceIcon(i, hIconT, pi);
  2851. DestroyIcon(hIconT);
  2852. }
  2853. }
  2854. return _ReplaceIcon(i, hIcon,pi);
  2855. }
  2856. // make a dithered copy of the source image in the destination image.
  2857. // allows placing of the final image in the destination.
  2858. HRESULT CImageList::CopyDitherImage(WORD iDst, int xDst, int yDst, IUnknown* punkSrc, int iSrc, UINT fStyle)
  2859. {
  2860. IImageList* pux;
  2861. HRESULT hr = punkSrc->QueryInterface(IID_PPV_ARG(IImageList, &pux));
  2862. if (FAILED(hr))
  2863. return hr;
  2864. RECT rc;
  2865. int x, y;
  2866. GetImageRect(iDst, &rc);
  2867. // coordinates in destination image list
  2868. x = xDst + rc.left;
  2869. y = yDst + rc.top;
  2870. fStyle &= ILD_OVERLAYMASK;
  2871. WimpyDrawEx(pux, iSrc, _hdcImage, x, y, 0, 0, CLR_DEFAULT, CLR_NONE, ILD_IMAGE | fStyle);
  2872. //
  2873. // dont dither the mask on a hicolor device, we will draw the image
  2874. // with blending while dragging.
  2875. //
  2876. if (_hdcMask && GetScreenDepth() > 8)
  2877. {
  2878. WimpyDrawEx(pux, iSrc, _hdcMask, x, y, 0, 0, CLR_NONE, CLR_NONE, ILD_MASK | fStyle);
  2879. }
  2880. else if (_hdcMask)
  2881. {
  2882. WimpyDrawEx(pux, iSrc, _hdcMask, x, y, 0, 0, CLR_NONE, CLR_NONE, ILD_BLEND50|ILD_MASK | fStyle);
  2883. }
  2884. if ((_flags & ILC_COLORMASK) == ILC_COLOR32)
  2885. {
  2886. SetItemFlags(iDst, _HasAlpha(iDst)?ILIF_ALPHA:0);
  2887. }
  2888. _ResetBkColor(iDst, iDst+1, _clrBk);
  2889. pux->Release();
  2890. return hr;
  2891. }
  2892. //
  2893. // ImageList_CopyBitmap
  2894. //
  2895. // Worker function for ImageList_Duplicate.
  2896. //
  2897. // Given a bitmap and an hdc, creates and returns a copy of the passed in bitmap.
  2898. //
  2899. HBITMAP CImageList::_CopyBitmap(HBITMAP hbm, HDC hdc)
  2900. {
  2901. ASSERT(hbm);
  2902. BITMAP bm;
  2903. HBITMAP hbmCopy = NULL;
  2904. if (GetObject(hbm, sizeof(bm), &bm) == sizeof(bm))
  2905. {
  2906. ENTERCRITICAL;
  2907. if (hbmCopy = CreateCompatibleBitmap(hdc, bm.bmWidth, bm.bmHeight))
  2908. {
  2909. CImageList::SelectDstBitmap(hbmCopy);
  2910. BitBlt(g_hdcDst, 0, 0, bm.bmWidth, bm.bmHeight,
  2911. hdc, 0, 0, SRCCOPY);
  2912. CImageList::SelectDstBitmap(NULL);
  2913. }
  2914. LEAVECRITICAL;
  2915. }
  2916. return hbmCopy;
  2917. }
  2918. HBITMAP CImageList::_CopyDIBBitmap(HBITMAP hbm, HDC hdc, RGBQUAD** ppargb)
  2919. {
  2920. ASSERT(hbm);
  2921. BITMAP bm;
  2922. HBITMAP hbmCopy = NULL;
  2923. if (GetObject(hbm, sizeof(bm), &bm) == sizeof(bm))
  2924. {
  2925. ENTERCRITICAL;
  2926. hbmCopy = _CreateBitmap(bm.bmWidth, bm.bmHeight, ppargb);
  2927. if (hbmCopy)
  2928. {
  2929. CImageList::SelectDstBitmap(hbmCopy);
  2930. BitBlt(g_hdcDst, 0, 0, bm.bmWidth, bm.bmHeight,
  2931. hdc, 0, 0, SRCCOPY);
  2932. CImageList::SelectDstBitmap(NULL);
  2933. }
  2934. LEAVECRITICAL;
  2935. }
  2936. return hbmCopy;
  2937. }
  2938. HRESULT CImageList::Clone(REFIID riid, void** ppv)
  2939. {
  2940. HBITMAP hbmImageI;
  2941. HBITMAP hbmMaskI = NULL;
  2942. RGBQUAD* pargbImageI;
  2943. HDSA dsaFlags = NULL;
  2944. HRESULT hr = S_OK;
  2945. CImageList* pimlCopy = NULL;
  2946. *ppv = NULL;
  2947. ENTERCRITICAL;
  2948. hbmImageI = _CopyDIBBitmap(_hbmImage, _hdcImage, &pargbImageI);
  2949. if (!hbmImageI)
  2950. hr = E_OUTOFMEMORY;
  2951. if (SUCCEEDED(hr))
  2952. {
  2953. if (_hdcMask)
  2954. {
  2955. hbmMaskI = _CopyBitmap(_hbmMask, _hdcMask);
  2956. if (!hbmMaskI)
  2957. hr = E_OUTOFMEMORY;
  2958. }
  2959. if (SUCCEEDED(hr) && (_flags & ILC_COLORMASK) == ILC_COLOR32)
  2960. {
  2961. dsaFlags = DSA_Create(sizeof(DWORD), _cGrow);
  2962. if (dsaFlags)
  2963. {
  2964. DWORD dw;
  2965. for (int i = 0; i < _cImage; i++)
  2966. {
  2967. DSA_GetItem(_dsaFlags, i, &dw);
  2968. if (!DSA_SetItem(dsaFlags, i, &dw))
  2969. {
  2970. hr = E_OUTOFMEMORY;
  2971. break;
  2972. }
  2973. }
  2974. }
  2975. }
  2976. if (SUCCEEDED(hr))
  2977. {
  2978. pimlCopy = CImageList::Create(_cx, _cy, _flags, 0, _cGrow);
  2979. if (pimlCopy)
  2980. {
  2981. // Slam in our bitmap copies and delete the old ones
  2982. SelectObject(pimlCopy->_hdcImage, hbmImageI);
  2983. CImageList::_DeleteBitmap(pimlCopy->_hbmImage);
  2984. if (pimlCopy->_hdcMask)
  2985. {
  2986. SelectObject(pimlCopy->_hdcMask, hbmMaskI);
  2987. CImageList::_DeleteBitmap(pimlCopy->_hbmMask);
  2988. }
  2989. if (pimlCopy->_dsaFlags)
  2990. DSA_Destroy(pimlCopy->_dsaFlags);
  2991. pimlCopy->_dsaFlags = dsaFlags;
  2992. pimlCopy->_hbmImage = hbmImageI;
  2993. pimlCopy->_pargbImage = pargbImageI;
  2994. pimlCopy->_hbmMask = hbmMaskI;
  2995. // Make sure other info is correct
  2996. pimlCopy->_cImage = _cImage;
  2997. pimlCopy->_cAlloc = _cAlloc;
  2998. pimlCopy->_cStrip = _cStrip;
  2999. pimlCopy->_clrBlend = _clrBlend;
  3000. pimlCopy->_clrBk = _clrBk;
  3001. // Delete the old brush and create the correct one
  3002. if (pimlCopy->_hbrBk)
  3003. DeleteObject(pimlCopy->_hbrBk);
  3004. if (pimlCopy->_clrBk == CLR_NONE)
  3005. {
  3006. pimlCopy->_hbrBk = (HBRUSH)GetStockObject(BLACK_BRUSH);
  3007. pimlCopy->_fSolidBk = TRUE;
  3008. }
  3009. else
  3010. {
  3011. pimlCopy->_hbrBk = CreateSolidBrush(pimlCopy->_clrBk);
  3012. pimlCopy->_fSolidBk = GetNearestColor32(pimlCopy->_hdcImage, pimlCopy->_clrBk) == pimlCopy->_clrBk;
  3013. }
  3014. }
  3015. }
  3016. LEAVECRITICAL;
  3017. }
  3018. if (FAILED(hr))
  3019. {
  3020. if (hbmImageI)
  3021. CImageList::_DeleteBitmap(hbmImageI);
  3022. if (hbmMaskI)
  3023. CImageList::_DeleteBitmap(hbmMaskI);
  3024. if (dsaFlags)
  3025. DSA_Destroy(dsaFlags);
  3026. }
  3027. if (pimlCopy)
  3028. {
  3029. hr = pimlCopy->QueryInterface(riid, ppv);
  3030. pimlCopy->Release();
  3031. }
  3032. return hr;
  3033. }
  3034. void CImageList::_Merge(IImageList* pux, int i, int dx, int dy)
  3035. {
  3036. if (_hdcMask)
  3037. {
  3038. IImageListPriv* puxp;
  3039. if (SUCCEEDED(pux->QueryInterface(IID_PPV_ARG(IImageListPriv, &puxp))))
  3040. {
  3041. HDC hdcMaskI;
  3042. if (SUCCEEDED(puxp->GetPrivateGoo(NULL, NULL, NULL, &hdcMaskI)) && hdcMaskI)
  3043. {
  3044. RECT rcMerge;
  3045. int cxI, cyI;
  3046. pux->GetIconSize(&cxI, &cyI);
  3047. UINT uFlags = 0;
  3048. puxp->GetFlags(&uFlags);
  3049. pux->GetImageRect(i, &rcMerge);
  3050. BitBlt(_hdcMask, dx, dy, cxI, cyI,
  3051. hdcMaskI, rcMerge.left, rcMerge.top, SRCAND);
  3052. }
  3053. puxp->Release();
  3054. }
  3055. }
  3056. WimpyDraw(pux, i, _hdcImage, dx, dy, ILD_TRANSPARENT | ILD_PRESERVEALPHA);
  3057. if ((_flags & ILC_COLORMASK) == ILC_COLOR32)
  3058. SetItemFlags(i, _HasAlpha(i)? ILIF_ALPHA : 0);
  3059. }
  3060. HRESULT CImageList::_Merge(int i1, IUnknown* punk, int i2, int dx, int dy, CImageList** ppiml)
  3061. {
  3062. CImageList* pimlNew = NULL;
  3063. IImageListPriv* puxp;
  3064. HRESULT hr = punk->QueryInterface(IID_PPV_ARG(IImageListPriv, &puxp));
  3065. if (SUCCEEDED(hr))
  3066. {
  3067. IImageList* pux;
  3068. hr = punk->QueryInterface(IID_PPV_ARG(IImageList, &pux));
  3069. if (SUCCEEDED(hr))
  3070. {
  3071. RECT rcNew;
  3072. RECT rc1;
  3073. RECT rc2;
  3074. int cxI, cyI;
  3075. int c1, c2;
  3076. UINT wFlags;
  3077. UINT uSrcFlags;
  3078. puxp->GetFlags(&uSrcFlags);
  3079. pux->GetIconSize(&cxI, &cyI);
  3080. ENTERCRITICAL;
  3081. SetRect(&rc1, 0, 0, _cx, _cy);
  3082. SetRect(&rc2, dx, dy, cxI + dx, cyI + dy);
  3083. UnionRect(&rcNew, &rc1, &rc2);
  3084. cxI = RECTWIDTH(rcNew);
  3085. cyI = RECTHEIGHT(rcNew);
  3086. //
  3087. // If one of images are shared, create a shared image.
  3088. //
  3089. wFlags = (_flags | uSrcFlags) & ~ILC_COLORMASK;
  3090. c1 = (_flags & ILC_COLORMASK);
  3091. c2 = (uSrcFlags & ILC_COLORMASK);
  3092. if ((c1 == 16 || c1 == 32) && c2 == ILC_COLORDDB)
  3093. {
  3094. c2 = c1;
  3095. }
  3096. wFlags |= max(c1,c2);
  3097. pimlNew = CImageList::Create(cxI, cyI, ILC_MASK|wFlags, 1, 0);
  3098. if (pimlNew)
  3099. {
  3100. pimlNew->_cImage++;
  3101. if (pimlNew->_hdcMask)
  3102. PatBlt(pimlNew->_hdcMask, 0, 0, cxI, cyI, WHITENESS);
  3103. PatBlt(pimlNew->_hdcImage, 0, 0, cxI, cyI, BLACKNESS);
  3104. pimlNew->_Merge(SAFECAST(this, IImageList*), i1, rc1.left - rcNew.left, rc1.top - rcNew.top);
  3105. pimlNew->_Merge(pux, i2, rc2.left - rcNew.left, rc2.top - rcNew.top);
  3106. }
  3107. else
  3108. hr = E_OUTOFMEMORY;
  3109. LEAVECRITICAL;
  3110. pux->Release();
  3111. }
  3112. puxp->Release();
  3113. }
  3114. *ppiml = pimlNew;
  3115. return hr;
  3116. }
  3117. HRESULT CImageList::Merge(int i1, IUnknown* punk, int i2, int dx, int dy, REFIID riid, void** ppv)
  3118. {
  3119. CImageList* piml;
  3120. HRESULT hr = _Merge(i1, punk, i2, dx, dy, &piml);
  3121. if (piml)
  3122. {
  3123. hr = piml->QueryInterface(riid, ppv);
  3124. piml->Release();
  3125. }
  3126. return hr;
  3127. }
  3128. HRESULT CImageList::GetImageRectInverted(int i, RECT * prcImage)
  3129. {
  3130. int x, y;
  3131. ASSERT(prcImage);
  3132. ASSERT(_cStrip == 1); // If not, modify below to accomodate
  3133. if (!prcImage || !IsImageListIndex(i))
  3134. return E_FAIL;
  3135. x = 0;
  3136. y = (_cy * _cAlloc) - (_cy * i) - _cy;
  3137. SetRect(prcImage, x, y, x + _cx, y + _cy);
  3138. return S_OK;
  3139. }
  3140. HRESULT CImageList::GetImageRect(int i, RECT * prcImage)
  3141. {
  3142. int x, y;
  3143. ASSERT(prcImage);
  3144. if (!prcImage || !IsImageListIndex(i))
  3145. return E_FAIL;
  3146. x = _cx * (i % _cStrip);
  3147. y = _cy * (i / _cStrip);
  3148. SetRect(prcImage, x, y, x + _cx, y + _cy);
  3149. return S_OK;
  3150. }
  3151. BOOL CImageList::GetSpareImageRect(RECT * prcImage)
  3152. {
  3153. BOOL fRet = FALSE;
  3154. if (_cImage < _cAlloc)
  3155. {
  3156. // special hacking to use the one scratch image at tail of list :)
  3157. _cImage++;
  3158. fRet = (S_OK == GetImageRect(_cImage-1, prcImage));
  3159. _cImage--;
  3160. }
  3161. return fRet;
  3162. }
  3163. BOOL CImageList::GetSpareImageRectInverted(RECT * prcImage)
  3164. {
  3165. BOOL fRet = FALSE;
  3166. if (_cImage < _cAlloc)
  3167. {
  3168. // special hacking to use the one scratch image at tail of list :)
  3169. _cImage++;
  3170. fRet = (S_OK == GetImageRectInverted(_cImage-1, prcImage));
  3171. _cImage--;
  3172. }
  3173. return fRet;
  3174. }
  3175. // Drag Drop
  3176. // copy an image from one imagelist to another at x,y within iDst in pimlDst.
  3177. // pimlDst's image size should be larger than pimlSrc
  3178. void CImageList::_CopyOneImage(int iDst, int x, int y, CImageList* piml, int iSrc)
  3179. {
  3180. RECT rcSrc, rcDst;
  3181. piml->GetImageRect(iSrc, &rcSrc);
  3182. GetImageRect(iDst, &rcDst);
  3183. if (piml->_hdcMask && _hdcMask)
  3184. {
  3185. BitBlt(_hdcMask, rcDst.left + x, rcDst.top + y, piml->_cx, piml->_cy,
  3186. piml->_hdcMask, rcSrc.left, rcSrc.top, SRCCOPY);
  3187. }
  3188. BitBlt(_hdcImage, rcDst.left + x, rcDst.top + y, piml->_cx, piml->_cy,
  3189. piml->_hdcImage, rcSrc.left, rcSrc.top, SRCCOPY);
  3190. if ((_flags & ILC_COLORMASK) == ILC_COLOR32)
  3191. SetItemFlags(iDst, _HasAlpha(iDst)? ILIF_ALPHA : 0);
  3192. }
  3193. //
  3194. // Cached bitmaps that we use during drag&drop. We re-use those bitmaps
  3195. // across multiple drag session as far as the image size is the same.
  3196. //
  3197. struct DRAGRESTOREBMP
  3198. {
  3199. int BitsPixel;
  3200. HBITMAP hbmOffScreen;
  3201. HBITMAP hbmRestore;
  3202. SIZE sizeRestore;
  3203. }
  3204. g_drb =
  3205. {
  3206. 0, NULL, NULL, {-1,-1}
  3207. };
  3208. BOOL CImageList::CreateDragBitmaps()
  3209. {
  3210. HDC hdc;
  3211. hdc = GetDC(NULL);
  3212. if (_cx != g_drb.sizeRestore.cx ||
  3213. _cy != g_drb.sizeRestore.cy ||
  3214. GetDeviceCaps(hdc, BITSPIXEL) != g_drb.BitsPixel)
  3215. {
  3216. ImageList_DeleteDragBitmaps();
  3217. g_drb.BitsPixel = GetDeviceCaps(hdc, BITSPIXEL);
  3218. g_drb.sizeRestore.cx = _cx;
  3219. g_drb.sizeRestore.cy = _cy;
  3220. g_drb.hbmRestore = CreateColorBitmap(g_drb.sizeRestore.cx, g_drb.sizeRestore.cy);
  3221. g_drb.hbmOffScreen = CreateColorBitmap(g_drb.sizeRestore.cx * 2 - 1, g_drb.sizeRestore.cy * 2 - 1);
  3222. if (!g_drb.hbmRestore || !g_drb.hbmOffScreen)
  3223. {
  3224. ImageList_DeleteDragBitmaps();
  3225. ReleaseDC(NULL, hdc);
  3226. return FALSE;
  3227. }
  3228. }
  3229. ReleaseDC(NULL, hdc);
  3230. return TRUE;
  3231. }
  3232. void ImageList_DeleteDragBitmaps()
  3233. {
  3234. if (g_drb.hbmRestore)
  3235. {
  3236. CImageList::_DeleteBitmap(g_drb.hbmRestore);
  3237. g_drb.hbmRestore = NULL;
  3238. }
  3239. if (g_drb.hbmOffScreen)
  3240. {
  3241. CImageList::_DeleteBitmap(g_drb.hbmOffScreen);
  3242. g_drb.hbmOffScreen = NULL;
  3243. }
  3244. g_drb.sizeRestore.cx = -1;
  3245. g_drb.sizeRestore.cy = -1;
  3246. }
  3247. //
  3248. // Drag context. We don't reuse none of them across two different
  3249. // drag sessions. I'm planning to allocate it for each session
  3250. // to minimize critical sections.
  3251. //
  3252. struct DRAGCONTEXT
  3253. {
  3254. CImageList* pimlDrag; // Image to be drawin while dragging
  3255. IImageList* puxCursor; // Overlap cursor image
  3256. CImageList* pimlDither; // Dithered image
  3257. IImageList* puxDragImage; // The context of the drag.
  3258. int iCursor; // Image index of the cursor
  3259. POINT ptDrag; // current drag position (hwndDC coords)
  3260. POINT ptDragHotspot;
  3261. POINT ptCursor;
  3262. BOOL fDragShow;
  3263. BOOL fHiColor;
  3264. HWND hwndDC;
  3265. }
  3266. g_dctx =
  3267. {
  3268. (CImageList*)NULL, (CImageList*)NULL, (CImageList*)NULL, (IImageList*)NULL,
  3269. -1,
  3270. {0, 0}, {0, 0}, {0, 0},
  3271. FALSE,
  3272. FALSE,
  3273. (HWND)NULL
  3274. };
  3275. HDC ImageList_GetDragDC()
  3276. {
  3277. HDC hdc = GetDCEx(g_dctx.hwndDC, NULL, DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE);
  3278. //
  3279. // If hdc is mirrored then mirror the 2 globals DCs.
  3280. //
  3281. if (IS_DC_RTL_MIRRORED(hdc))
  3282. {
  3283. SET_DC_RTL_MIRRORED(g_hdcDst);
  3284. SET_DC_RTL_MIRRORED(g_hdcSrc);
  3285. }
  3286. return hdc;
  3287. }
  3288. void ImageList_ReleaseDragDC(HDC hdc)
  3289. {
  3290. //
  3291. // If the hdc is mirrored then unmirror the 2 globals DCs.
  3292. //
  3293. if (IS_DC_RTL_MIRRORED(hdc))
  3294. {
  3295. SET_DC_LAYOUT(g_hdcDst, 0);
  3296. SET_DC_LAYOUT(g_hdcSrc, 0);
  3297. }
  3298. ReleaseDC(g_dctx.hwndDC, hdc);
  3299. }
  3300. //
  3301. // x, y -- Specifies the initial cursor position in the coords of hwndLock,
  3302. // which is specified by the previous ImageList_StartDrag call.
  3303. //
  3304. HRESULT CImageList::DragMove(int x, int y)
  3305. {
  3306. int IncOne = 0;
  3307. ENTERCRITICAL;
  3308. if (g_dctx.fDragShow)
  3309. {
  3310. RECT rcOld, rcNew, rcBounds;
  3311. int dx, dy;
  3312. dx = x - g_dctx.ptDrag.x;
  3313. dy = y - g_dctx.ptDrag.y;
  3314. rcOld.left = g_dctx.ptDrag.x - g_dctx.ptDragHotspot.x;
  3315. rcOld.top = g_dctx.ptDrag.y - g_dctx.ptDragHotspot.y;
  3316. rcOld.right = rcOld.left + g_drb.sizeRestore.cx;
  3317. rcOld.bottom = rcOld.top + g_drb.sizeRestore.cy;
  3318. rcNew = rcOld;
  3319. OffsetRect(&rcNew, dx, dy);
  3320. if (!IntersectRect(&rcBounds, &rcOld, &rcNew))
  3321. {
  3322. //
  3323. // No intersection. Simply hide the old one and show the new one.
  3324. //
  3325. ImageList_DragShowNolock(FALSE);
  3326. g_dctx.ptDrag.x = x;
  3327. g_dctx.ptDrag.y = y;
  3328. ImageList_DragShowNolock(TRUE);
  3329. }
  3330. else
  3331. {
  3332. //
  3333. // Some intersection.
  3334. //
  3335. HDC hdcScreen;
  3336. int cx, cy;
  3337. UnionRect(&rcBounds, &rcOld, &rcNew);
  3338. hdcScreen = ImageList_GetDragDC();
  3339. if (hdcScreen)
  3340. {
  3341. //
  3342. // If the DC is RTL mirrored, then restrict the
  3343. // screen bitmap not to go beyond the screen since
  3344. // we will end up copying the wrong bits from the
  3345. // hdcScreen to the hbmOffScreen when the DC is mirrored.
  3346. // GDI will skip invalid screen coord from the screen into
  3347. // the destination bitmap. This will result in copying un-init
  3348. // bits back to the screen (since the screen is mirrored).
  3349. // [samera]
  3350. //
  3351. if (IS_DC_RTL_MIRRORED(hdcScreen))
  3352. {
  3353. RECT rcWindow;
  3354. GetWindowRect(g_dctx.hwndDC, &rcWindow);
  3355. rcWindow.right -= rcWindow.left;
  3356. if (rcBounds.right > rcWindow.right)
  3357. {
  3358. rcBounds.right = rcWindow.right;
  3359. }
  3360. if (rcBounds.left < 0)
  3361. {
  3362. rcBounds.left = 0;
  3363. }
  3364. }
  3365. cx = rcBounds.right - rcBounds.left;
  3366. cy = rcBounds.bottom - rcBounds.top;
  3367. //
  3368. // Copy the union rect from the screen to hbmOffScreen.
  3369. //
  3370. CImageList::SelectDstBitmap(g_drb.hbmOffScreen);
  3371. BitBlt(g_hdcDst, 0, 0, cx, cy,
  3372. hdcScreen, rcBounds.left, rcBounds.top, SRCCOPY);
  3373. //
  3374. // Hide the cursor on the hbmOffScreen by copying hbmRestore.
  3375. //
  3376. CImageList::SelectSrcBitmap(g_drb.hbmRestore);
  3377. BitBlt(g_hdcDst,
  3378. rcOld.left - rcBounds.left,
  3379. rcOld.top - rcBounds.top,
  3380. g_drb.sizeRestore.cx, g_drb.sizeRestore.cy,
  3381. g_hdcSrc, 0, 0, SRCCOPY);
  3382. //
  3383. // Copy the original screen bits to hbmRestore
  3384. //
  3385. BitBlt(g_hdcSrc, 0, 0, g_drb.sizeRestore.cx, g_drb.sizeRestore.cy,
  3386. g_hdcDst,
  3387. rcNew.left - rcBounds.left,
  3388. rcNew.top - rcBounds.top,
  3389. SRCCOPY);
  3390. //
  3391. // Draw the image on hbmOffScreen
  3392. //
  3393. if (g_dctx.fHiColor)
  3394. {
  3395. WimpyDrawEx(SAFECAST(g_dctx.pimlDrag, IImageList*), 0, g_hdcDst,
  3396. rcNew.left - rcBounds.left + IncOne,
  3397. rcNew.top - rcBounds.top, 0, 0, CLR_NONE, CLR_NONE, ILD_BLEND50);
  3398. if (g_dctx.puxCursor)
  3399. {
  3400. WimpyDraw(g_dctx.puxCursor, g_dctx.iCursor, g_hdcDst,
  3401. rcNew.left - rcBounds.left + g_dctx.ptCursor.x + IncOne,
  3402. rcNew.top - rcBounds.top + g_dctx.ptCursor.y,
  3403. ILD_NORMAL);
  3404. }
  3405. }
  3406. else
  3407. {
  3408. WimpyDraw(SAFECAST(g_dctx.pimlDrag, IImageList*), 0, g_hdcDst,
  3409. rcNew.left - rcBounds.left + IncOne,
  3410. rcNew.top - rcBounds.top, ILD_NORMAL);
  3411. }
  3412. //
  3413. // Copy the hbmOffScreen back to the screen.
  3414. //
  3415. BitBlt(hdcScreen, rcBounds.left, rcBounds.top, cx, cy,
  3416. g_hdcDst, 0, 0, SRCCOPY);
  3417. ImageList_ReleaseDragDC(hdcScreen);
  3418. }
  3419. g_dctx.ptDrag.x = x;
  3420. g_dctx.ptDrag.y = y;
  3421. }
  3422. }
  3423. LEAVECRITICAL;
  3424. return S_OK;
  3425. }
  3426. HRESULT CImageList::BeginDrag(int iTrack, int dxHotspot, int dyHotspot)
  3427. {
  3428. HRESULT hr = E_ACCESSDENIED;
  3429. ENTERCRITICAL;
  3430. if (!g_dctx.pimlDrag)
  3431. {
  3432. UINT newflags;
  3433. int cxI = 0, cyI = 0;
  3434. g_dctx.fDragShow = FALSE;
  3435. g_dctx.hwndDC = NULL;
  3436. g_dctx.fHiColor = GetScreenDepth() > 8;
  3437. newflags = _flags|ILC_SHARED;
  3438. if (g_dctx.fHiColor)
  3439. {
  3440. UINT uColorFlag = ILC_COLOR16;
  3441. if (GetScreenDepth() == 32 || GetScreenDepth() == 24)
  3442. {
  3443. uColorFlag = ILC_COLOR32;
  3444. }
  3445. newflags = (newflags & ~ILC_COLORMASK) | uColorFlag;
  3446. }
  3447. g_dctx.pimlDither = CImageList::Create(_cx, _cy, newflags, 1, 0);
  3448. if (g_dctx.pimlDither)
  3449. {
  3450. g_dctx.pimlDither->_cImage++;
  3451. g_dctx.ptDragHotspot.x = dxHotspot;
  3452. g_dctx.ptDragHotspot.y = dyHotspot;
  3453. g_dctx.pimlDither->_CopyOneImage(0, 0, 0, this, iTrack);
  3454. hr = ImageList_SetDragImage(NULL, 0, dxHotspot, dyHotspot)? S_OK : E_FAIL;
  3455. }
  3456. }
  3457. LEAVECRITICAL;
  3458. return hr;
  3459. }
  3460. HRESULT CImageList::DragEnter(HWND hwndLock, int x, int y)
  3461. {
  3462. HRESULT hr = S_FALSE;
  3463. hwndLock = hwndLock ? hwndLock : GetDesktopWindow();
  3464. ENTERCRITICAL;
  3465. if (!g_dctx.hwndDC)
  3466. {
  3467. g_dctx.hwndDC = hwndLock;
  3468. g_dctx.ptDrag.x = x;
  3469. g_dctx.ptDrag.y = y;
  3470. ImageList_DragShowNolock(TRUE);
  3471. hr = S_OK;
  3472. }
  3473. LEAVECRITICAL;
  3474. return hr;
  3475. }
  3476. HRESULT CImageList::DragLeave(HWND hwndLock)
  3477. {
  3478. HRESULT hr = S_FALSE;
  3479. hwndLock = hwndLock ? hwndLock : GetDesktopWindow();
  3480. ENTERCRITICAL;
  3481. if (g_dctx.hwndDC == hwndLock)
  3482. {
  3483. ImageList_DragShowNolock(FALSE);
  3484. g_dctx.hwndDC = NULL;
  3485. hr = S_OK;
  3486. }
  3487. LEAVECRITICAL;
  3488. return hr;
  3489. }
  3490. HRESULT CImageList::DragShowNolock(BOOL fShow)
  3491. {
  3492. HDC hdcScreen;
  3493. int x, y;
  3494. int IncOne = 0;
  3495. x = g_dctx.ptDrag.x - g_dctx.ptDragHotspot.x;
  3496. y = g_dctx.ptDrag.y - g_dctx.ptDragHotspot.y;
  3497. if (!g_dctx.pimlDrag)
  3498. return E_ACCESSDENIED;
  3499. //
  3500. // REVIEW: Why this block is in the critical section? We are supposed
  3501. // to have only one dragging at a time, aren't we?
  3502. //
  3503. ENTERCRITICAL;
  3504. if (fShow && !g_dctx.fDragShow)
  3505. {
  3506. hdcScreen = ImageList_GetDragDC();
  3507. CImageList::SelectSrcBitmap(g_drb.hbmRestore);
  3508. BitBlt(g_hdcSrc, 0, 0, g_drb.sizeRestore.cx, g_drb.sizeRestore.cy,
  3509. hdcScreen, x, y, SRCCOPY);
  3510. if (g_dctx.fHiColor)
  3511. {
  3512. WimpyDrawEx(SAFECAST(g_dctx.pimlDrag, IImageList*), 0, hdcScreen, x + IncOne, y, 0, 0, CLR_NONE, CLR_NONE, ILD_BLEND50);
  3513. if (g_dctx.puxCursor)
  3514. {
  3515. WimpyDraw(g_dctx.puxCursor, g_dctx.iCursor, hdcScreen,
  3516. x + g_dctx.ptCursor.x + IncOne, y + g_dctx.ptCursor.y, ILD_NORMAL);
  3517. }
  3518. }
  3519. else
  3520. {
  3521. WimpyDraw(SAFECAST(g_dctx.pimlDrag, IImageList*), 0, hdcScreen, x + IncOne, y, ILD_NORMAL);
  3522. }
  3523. ImageList_ReleaseDragDC(hdcScreen);
  3524. }
  3525. else if (!fShow && g_dctx.fDragShow)
  3526. {
  3527. hdcScreen = ImageList_GetDragDC();
  3528. CImageList::SelectSrcBitmap(g_drb.hbmRestore);
  3529. BitBlt(hdcScreen, x, y, g_drb.sizeRestore.cx, g_drb.sizeRestore.cy,
  3530. g_hdcSrc, 0, 0, SRCCOPY);
  3531. ImageList_ReleaseDragDC(hdcScreen);
  3532. }
  3533. g_dctx.fDragShow = fShow;
  3534. LEAVECRITICAL;
  3535. return S_OK;
  3536. }
  3537. // this hotspot stuff is broken in design
  3538. BOOL ImageList_MergeDragImages(int dxHotspot, int dyHotspot)
  3539. {
  3540. CImageList* pimlNew;
  3541. BOOL fRet = FALSE;
  3542. if (g_dctx.pimlDither)
  3543. {
  3544. if (g_dctx.puxCursor)
  3545. {
  3546. IImageList* pux = NULL;
  3547. IImageListPriv* puxpCursor;
  3548. if (SUCCEEDED(g_dctx.puxCursor->QueryInterface(IID_PPV_ARG(IImageListPriv, &puxpCursor))))
  3549. {
  3550. // If the cursor list has a mirrored list, let's use that.
  3551. if (FAILED(puxpCursor->GetMirror(IID_PPV_ARG(IImageList, &pux))))
  3552. {
  3553. pux = g_dctx.puxCursor;
  3554. if (pux)
  3555. pux->AddRef();
  3556. }
  3557. puxpCursor->Release();
  3558. }
  3559. g_dctx.pimlDither->_Merge(0, pux, g_dctx.iCursor, dxHotspot, dyHotspot, &pimlNew);
  3560. if (pimlNew && pimlNew->CreateDragBitmaps())
  3561. {
  3562. // WARNING: Don't destroy pimlDrag if it is pimlDither.
  3563. if (g_dctx.pimlDrag && (g_dctx.pimlDrag != g_dctx.pimlDither))
  3564. {
  3565. g_dctx.pimlDrag->Release();
  3566. }
  3567. g_dctx.pimlDrag = pimlNew;
  3568. fRet = TRUE;
  3569. }
  3570. pux->Release();
  3571. }
  3572. else
  3573. {
  3574. if (g_dctx.pimlDither->CreateDragBitmaps())
  3575. {
  3576. g_dctx.pimlDrag = g_dctx.pimlDither;
  3577. fRet = TRUE;
  3578. }
  3579. }
  3580. }
  3581. else
  3582. {
  3583. // not an error case if both aren't set yet
  3584. // only an error if we actually tried the merge and failed
  3585. fRet = TRUE;
  3586. }
  3587. return fRet;
  3588. }
  3589. BOOL ImageList_SetDragImage(HIMAGELIST piml, int i, int dxHotspot, int dyHotspot)
  3590. {
  3591. BOOL fVisible = g_dctx.fDragShow;
  3592. BOOL fRet;
  3593. ENTERCRITICAL;
  3594. if (fVisible)
  3595. ImageList_DragShowNolock(FALSE);
  3596. // only do this last step if everything is there.
  3597. fRet = ImageList_MergeDragImages(dxHotspot, dyHotspot);
  3598. if (fVisible)
  3599. ImageList_DragShowNolock(TRUE);
  3600. LEAVECRITICAL;
  3601. return fRet;
  3602. }
  3603. HRESULT CImageList::GetDragImage(POINT * ppt, POINT * pptHotspot, REFIID riid, void** ppv)
  3604. {
  3605. if (ppt)
  3606. {
  3607. ppt->x = g_dctx.ptDrag.x;
  3608. ppt->y = g_dctx.ptDrag.y;
  3609. }
  3610. if (pptHotspot)
  3611. {
  3612. pptHotspot->x = g_dctx.ptDragHotspot.x;
  3613. pptHotspot->y = g_dctx.ptDragHotspot.y;
  3614. }
  3615. if (g_dctx.pimlDrag)
  3616. {
  3617. return g_dctx.pimlDrag->QueryInterface(riid, ppv);
  3618. }
  3619. return E_ACCESSDENIED;
  3620. }
  3621. HRESULT CImageList::GetItemFlags(int i, DWORD *dwFlags)
  3622. {
  3623. if (IsImageListIndex(i) && _dsaFlags)
  3624. {
  3625. *dwFlags = _GetItemFlags(i);
  3626. return S_OK;
  3627. }
  3628. return E_INVALIDARG;
  3629. }
  3630. HRESULT CImageList::GetOverlayImage(int iOverlay, int* piIndex)
  3631. {
  3632. if (iOverlay <= 0 || iOverlay >= NUM_OVERLAY_IMAGES)
  3633. return E_INVALIDARG;
  3634. *piIndex = _aOverlayIndexes[iOverlay - 1];
  3635. return S_OK;
  3636. }
  3637. HRESULT CImageList::SetDragCursorImage(IUnknown* punk, int i, int dxHotspot, int dyHotspot)
  3638. {
  3639. HRESULT hr = E_INVALIDARG;
  3640. BOOL fVisible = g_dctx.fDragShow;
  3641. IImageList* pux;
  3642. if (SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IImageList, &pux))))
  3643. {
  3644. ENTERCRITICAL;
  3645. // do work only if something has changed
  3646. if ((g_dctx.puxCursor != pux) || (g_dctx.iCursor != i))
  3647. {
  3648. if (fVisible)
  3649. ImageList_DragShowNolock(FALSE);
  3650. IImageList* puxOld = g_dctx.puxCursor;
  3651. g_dctx.puxCursor = pux;
  3652. g_dctx.puxCursor->AddRef();
  3653. if (puxOld)
  3654. puxOld->Release();
  3655. g_dctx.iCursor = i;
  3656. g_dctx.ptCursor.x = dxHotspot;
  3657. g_dctx.ptCursor.y = dyHotspot;
  3658. hr = ImageList_MergeDragImages(dxHotspot, dyHotspot)? S_OK : E_FAIL;
  3659. if (fVisible)
  3660. ImageList_DragShowNolock(TRUE);
  3661. }
  3662. LEAVECRITICAL;
  3663. pux->Release();
  3664. }
  3665. return hr;
  3666. }
  3667. HRESULT CImageList::EndDrag()
  3668. {
  3669. ENTERCRITICAL;
  3670. ImageList_DragShowNolock(FALSE);
  3671. // WARNING: Don't destroy pimlDrag if it is pimlDither.
  3672. if (g_dctx.pimlDrag && (g_dctx.pimlDrag != g_dctx.pimlDither))
  3673. {
  3674. g_dctx.pimlDrag->Release();
  3675. }
  3676. g_dctx.pimlDrag = NULL;
  3677. if (g_dctx.pimlDither)
  3678. {
  3679. g_dctx.pimlDither->Release();
  3680. g_dctx.pimlDither = NULL;
  3681. }
  3682. if (g_dctx.puxCursor)
  3683. {
  3684. g_dctx.puxCursor->Release();
  3685. g_dctx.puxCursor = NULL;
  3686. }
  3687. g_dctx.iCursor = -1;
  3688. g_dctx.hwndDC = NULL;
  3689. LEAVECRITICAL;
  3690. return S_OK;
  3691. }
  3692. // APIs
  3693. BOOL WINAPI ImageList_SetDragCursorImage(HIMAGELIST piml, int i, int dxHotspot, int dyHotspot)
  3694. {
  3695. BOOL fRet = FALSE;
  3696. IUnknown* punk;
  3697. HRESULT hr = HIMAGELIST_QueryInterface(piml, IID_PPV_ARG(IUnknown, &punk));
  3698. if (SUCCEEDED(hr))
  3699. {
  3700. if (g_dctx.puxDragImage)
  3701. {
  3702. fRet = (S_OK == g_dctx.puxDragImage->SetDragCursorImage(punk, i, dxHotspot, dyHotspot));
  3703. }
  3704. punk->Release();
  3705. }
  3706. return fRet;
  3707. }
  3708. HIMAGELIST WINAPI ImageList_GetDragImage(POINT * ppt, POINT * pptHotspot)
  3709. {
  3710. if (g_dctx.puxDragImage)
  3711. {
  3712. IImageList* punk = NULL;
  3713. if (SUCCEEDED(g_dctx.puxDragImage->GetDragImage(ppt, pptHotspot, IID_PPV_ARG(IImageList, &punk))))
  3714. {
  3715. punk->Release();
  3716. }
  3717. return reinterpret_cast<HIMAGELIST>(punk);
  3718. }
  3719. return NULL;
  3720. }
  3721. void WINAPI ImageList_EndDrag()
  3722. {
  3723. ENTERCRITICAL;
  3724. if (g_dctx.puxDragImage)
  3725. {
  3726. g_dctx.puxDragImage->EndDrag();
  3727. g_dctx.puxDragImage->Release();
  3728. g_dctx.puxDragImage = NULL;
  3729. }
  3730. LEAVECRITICAL;
  3731. }
  3732. BOOL WINAPI ImageList_BeginDrag(HIMAGELIST pimlTrack, int iTrack, int dxHotspot, int dyHotspot)
  3733. {
  3734. IImageList* pux;
  3735. if (SUCCEEDED(HIMAGELIST_QueryInterface(pimlTrack, IID_PPV_ARG(IImageList, &pux))))
  3736. {
  3737. if (SUCCEEDED(pux->BeginDrag(iTrack, dxHotspot, dyHotspot)))
  3738. {
  3739. g_dctx.puxDragImage = pux;
  3740. return TRUE;
  3741. }
  3742. }
  3743. return FALSE;
  3744. }
  3745. BOOL WINAPI ImageList_DragEnter(HWND hwndLock, int x, int y)
  3746. {
  3747. BOOL fRet = FALSE;
  3748. if (g_dctx.puxDragImage)
  3749. {
  3750. fRet = (S_OK == g_dctx.puxDragImage->DragEnter(hwndLock, x, y));
  3751. }
  3752. return fRet;
  3753. }
  3754. BOOL WINAPI ImageList_DragMove(int x, int y)
  3755. {
  3756. BOOL fRet = FALSE;
  3757. if (g_dctx.puxDragImage)
  3758. {
  3759. fRet = (S_OK == g_dctx.puxDragImage->DragMove(x, y));
  3760. }
  3761. return fRet;
  3762. }
  3763. BOOL WINAPI ImageList_DragLeave(HWND hwndLock)
  3764. {
  3765. BOOL fRet = FALSE;
  3766. if (g_dctx.puxDragImage)
  3767. {
  3768. fRet = (S_OK == g_dctx.puxDragImage->DragLeave(hwndLock));
  3769. }
  3770. return fRet;
  3771. }
  3772. BOOL WINAPI ImageList_DragShowNolock(BOOL fShow)
  3773. {
  3774. BOOL fRet = FALSE;
  3775. if (g_dctx.puxDragImage)
  3776. {
  3777. fRet = (S_OK == g_dctx.puxDragImage->DragShowNolock(fShow));
  3778. }
  3779. return fRet;
  3780. }
  3781. //============================================================================
  3782. // ImageList_Clone - clone a image list
  3783. //
  3784. // create a new imagelist with the same properties as the given
  3785. // imagelist, except mabey a new icon size
  3786. //
  3787. // piml - imagelist to clone
  3788. // cx,cy - new icon size (0,0) to use clone icon size.
  3789. // flags - new flags (used if no clone)
  3790. // cInitial- initial size
  3791. // cGrow - grow value (used if no clone)
  3792. //============================================================================
  3793. EXTERN_C HIMAGELIST WINAPI ImageList_Clone(HIMAGELIST himl, int cx, int cy, UINT flags, int cInitial, int cGrow)
  3794. {
  3795. IImageListPriv* puxp;
  3796. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageListPriv, &puxp))))
  3797. {
  3798. // always use the clone flags
  3799. puxp->GetFlags(&flags);
  3800. IUnknown* punkMirror;
  3801. if (SUCCEEDED(puxp->GetMirror(IID_PPV_ARG(IUnknown, &punkMirror))))
  3802. {
  3803. flags |= ILC_MIRROR;
  3804. punkMirror->Release();
  3805. }
  3806. IImageList* pux;
  3807. if (SUCCEEDED(puxp->QueryInterface(IID_PPV_ARG(IImageList, &pux))))
  3808. {
  3809. int cxI, cyI;
  3810. pux->GetIconSize(&cxI, &cyI);
  3811. if (cx == 0)
  3812. cx = cxI;
  3813. if (cy == 0)
  3814. cy = cyI;
  3815. pux->Release();
  3816. }
  3817. puxp->Release();
  3818. }
  3819. return ImageList_Create(cx,cy,flags,cInitial,cGrow);
  3820. }
  3821. HRESULT WINAPI ImageList_CreateInstance(int cx, int cy, UINT flags, int cInitial, int cGrow, REFIID riid, void** ppv)
  3822. {
  3823. CImageList* piml=NULL;
  3824. HRESULT hr = E_OUTOFMEMORY;
  3825. *ppv = NULL;
  3826. piml = CImageList::Create(cx, cy, flags, cInitial, cGrow);
  3827. if (piml)
  3828. {
  3829. //
  3830. // Let's create a mirrored imagelist, if requested.
  3831. //
  3832. if (piml->_flags & ILC_MIRROR)
  3833. {
  3834. piml->_flags &= ~ILC_MIRROR;
  3835. piml->_pimlMirror = CImageList::Create(cx, cy, flags, cInitial, cGrow);
  3836. if (piml->_pimlMirror)
  3837. {
  3838. piml->_pimlMirror->_flags &= ~ILC_MIRROR;
  3839. }
  3840. }
  3841. hr = piml->QueryInterface(riid, ppv);
  3842. piml->Release();
  3843. }
  3844. return hr;
  3845. }
  3846. HIMAGELIST WINAPI ImageList_Create(int cx, int cy, UINT flags, int cInitial, int cGrow)
  3847. {
  3848. IImageList* pux;
  3849. ImageList_CreateInstance(cx, cy, flags, cInitial, cGrow, IID_PPV_ARG(IImageList, &pux));
  3850. return reinterpret_cast<HIMAGELIST>(pux);
  3851. }
  3852. //
  3853. // When this code is compiled Unicode, this implements the
  3854. // ANSI version of the ImageList_LoadImage api.
  3855. //
  3856. HIMAGELIST WINAPI ImageList_LoadImageA(HINSTANCE hi, LPCSTR lpbmp, int cx, int cGrow, COLORREF crMask, UINT uType, UINT uFlags)
  3857. {
  3858. HIMAGELIST lpResult;
  3859. LPWSTR lpBmpW;
  3860. if (!IS_INTRESOURCE(lpbmp))
  3861. {
  3862. lpBmpW = ProduceWFromA(CP_ACP, lpbmp);
  3863. if (!lpBmpW)
  3864. {
  3865. return NULL;
  3866. }
  3867. }
  3868. else
  3869. {
  3870. lpBmpW = (LPWSTR)lpbmp;
  3871. }
  3872. lpResult = ImageList_LoadImageW(hi, lpBmpW, cx, cGrow, crMask, uType, uFlags);
  3873. if (!IS_INTRESOURCE(lpbmp))
  3874. FreeProducedString(lpBmpW);
  3875. return lpResult;
  3876. }
  3877. HIMAGELIST WINAPI ImageList_LoadImageW(HINSTANCE hi, LPCTSTR lpbmp, int cx, int cGrow, COLORREF crMask, UINT uType, UINT uFlags)
  3878. {
  3879. HBITMAP hbmImage;
  3880. HIMAGELIST piml = NULL;
  3881. BITMAP bm;
  3882. int cy, cInitial;
  3883. UINT flags;
  3884. hbmImage = (HBITMAP)LoadImage(hi, lpbmp, uType, 0, 0, uFlags);
  3885. if (hbmImage && (sizeof(bm) == GetObject(hbmImage, sizeof(bm), &bm)))
  3886. {
  3887. // If cx is not stated assume it is the same as cy.
  3888. // ASSERT(cx);
  3889. cy = bm.bmHeight;
  3890. if (cx == 0)
  3891. cx = cy;
  3892. cInitial = bm.bmWidth / cx;
  3893. ENTERCRITICAL;
  3894. flags = 0;
  3895. if (crMask != CLR_NONE)
  3896. flags |= ILC_MASK;
  3897. if (bm.bmBits)
  3898. flags |= (bm.bmBitsPixel & ILC_COLORMASK);
  3899. piml = ImageList_Create(cx, cy, flags, cInitial, cGrow);
  3900. if (piml)
  3901. {
  3902. int added;
  3903. if (crMask == CLR_NONE)
  3904. added = ImageList_Add(piml, hbmImage, NULL);
  3905. else
  3906. added = ImageList_AddMasked(piml, hbmImage, crMask);
  3907. if (added < 0)
  3908. {
  3909. ImageList_Destroy(piml);
  3910. piml = NULL;
  3911. }
  3912. }
  3913. LEAVECRITICAL;
  3914. }
  3915. if (hbmImage)
  3916. DeleteObject(hbmImage);
  3917. return reinterpret_cast<HIMAGELIST>((IImageList*)piml);
  3918. }
  3919. //
  3920. //
  3921. #undef ImageList_AddIcon
  3922. EXTERN_C int WINAPI ImageList_AddIcon(HIMAGELIST himl, HICON hIcon)
  3923. {
  3924. return ImageList_ReplaceIcon(himl, -1, hIcon);
  3925. }
  3926. EXTERN_C void WINAPI ImageList_CopyDitherImage(HIMAGELIST himlDst, WORD iDst,
  3927. int xDst, int yDst, HIMAGELIST himlSrc, int iSrc, UINT fStyle)
  3928. {
  3929. IImageListPriv* puxp;
  3930. if (SUCCEEDED(HIMAGELIST_QueryInterface(himlDst, IID_PPV_ARG(IImageListPriv, &puxp))))
  3931. {
  3932. IUnknown* punk;
  3933. if (SUCCEEDED(HIMAGELIST_QueryInterface(himlSrc, IID_PPV_ARG(IUnknown, &punk))))
  3934. {
  3935. puxp->CopyDitherImage(iDst, xDst, yDst, punk, iSrc, fStyle);
  3936. punk->Release();
  3937. }
  3938. puxp->Release();
  3939. }
  3940. }
  3941. //
  3942. // ImageList_Duplicate
  3943. //
  3944. // Makes a copy of the passed in imagelist.
  3945. //
  3946. HIMAGELIST WINAPI ImageList_Duplicate(HIMAGELIST himl)
  3947. {
  3948. IImageList* pret = NULL;
  3949. IImageList* pux;
  3950. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageList, &pux))))
  3951. {
  3952. pux->Clone(IID_PPV_ARG(IImageList, &pret));
  3953. pux->Release();
  3954. }
  3955. return reinterpret_cast<HIMAGELIST>(pret);
  3956. }
  3957. BOOL WINAPI ImageList_Write(HIMAGELIST himl, LPSTREAM pstm)
  3958. {
  3959. BOOL fRet = FALSE;
  3960. IPersistStream* pps;
  3961. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IPersistStream, &pps))))
  3962. {
  3963. if (SUCCEEDED(pps->Save(pstm, TRUE)))
  3964. {
  3965. fRet = TRUE;
  3966. }
  3967. pps->Release();
  3968. }
  3969. return fRet;
  3970. }
  3971. HIMAGELIST WINAPI ImageList_Read(LPSTREAM pstm)
  3972. {
  3973. CImageList* piml = new CImageList();
  3974. if (piml)
  3975. {
  3976. if (SUCCEEDED(piml->Load(pstm)))
  3977. {
  3978. return reinterpret_cast<HIMAGELIST>((IImageList*)piml);
  3979. }
  3980. piml->Release();
  3981. }
  3982. return NULL;
  3983. }
  3984. WINCOMMCTRLAPI HRESULT WINAPI ImageList_ReadEx(DWORD dwFlags, LPSTREAM pstm, REFIID riid, PVOID* ppv)
  3985. {
  3986. HRESULT hr = E_OUTOFMEMORY;
  3987. CImageList* piml = new CImageList();
  3988. if (piml)
  3989. {
  3990. hr = piml->LoadEx(dwFlags, pstm);
  3991. if (SUCCEEDED(hr))
  3992. {
  3993. hr = piml->QueryInterface(riid, ppv);
  3994. }
  3995. piml->Release();
  3996. }
  3997. return hr;
  3998. }
  3999. WINCOMMCTRLAPI HRESULT WINAPI ImageList_WriteEx(HIMAGELIST himl, DWORD dwFlags, LPSTREAM pstm)
  4000. {
  4001. IImageListPersistStream* pps;
  4002. HRESULT hr = HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageListPersistStream, &pps));
  4003. if (SUCCEEDED(hr))
  4004. {
  4005. hr = pps->SaveEx(dwFlags, pstm);
  4006. pps->Release();
  4007. }
  4008. return hr;
  4009. }
  4010. BOOL WINAPI ImageList_GetImageRect(HIMAGELIST himl, int i, RECT * prcImage)
  4011. {
  4012. BOOL fRet = FALSE;
  4013. IImageList* pux;
  4014. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageList, &pux))))
  4015. {
  4016. if (SUCCEEDED(pux->GetImageRect(i, prcImage)))
  4017. {
  4018. fRet = TRUE;
  4019. }
  4020. pux->Release();
  4021. }
  4022. return fRet;
  4023. }
  4024. BOOL WINAPI ImageList_Destroy(HIMAGELIST himl)
  4025. {
  4026. BOOL fRet = FALSE;
  4027. IImageList* pux;
  4028. // Weirdness: We are doing a Query Interface first to verify that
  4029. // this is actually a valid imagelist, then we are calling release twice
  4030. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageList, &pux))))
  4031. {
  4032. // Release the interface we QI'd for
  4033. pux->Release();
  4034. // Release a second time to destroy the object
  4035. pux->Release();
  4036. fRet = TRUE;
  4037. }
  4038. return fRet;
  4039. }
  4040. int WINAPI ImageList_GetImageCount(HIMAGELIST himl)
  4041. {
  4042. int fRet = 0;
  4043. IImageList* pux;
  4044. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageList, &pux))))
  4045. {
  4046. pux->GetImageCount(&fRet);
  4047. pux->Release();
  4048. }
  4049. return fRet;
  4050. }
  4051. BOOL WINAPI ImageList_SetImageCount(HIMAGELIST himl, UINT uNewCount)
  4052. {
  4053. BOOL fRet = FALSE;
  4054. IImageList* pux;
  4055. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageList, &pux))))
  4056. {
  4057. fRet = (S_OK == pux->SetImageCount(uNewCount));
  4058. pux->Release();
  4059. }
  4060. return fRet;
  4061. }
  4062. int WINAPI ImageList_Add(HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask)
  4063. {
  4064. int fRet = -1;
  4065. IImageList* pux;
  4066. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageList, &pux))))
  4067. {
  4068. pux->Add(hbmImage, hbmMask, &fRet);
  4069. pux->Release();
  4070. }
  4071. return fRet;
  4072. }
  4073. int WINAPI ImageList_ReplaceIcon(HIMAGELIST himl, int i, HICON hicon)
  4074. {
  4075. int fRet = -1;
  4076. IImageList* pux;
  4077. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageList, &pux))))
  4078. {
  4079. pux->ReplaceIcon(i, hicon, &fRet);
  4080. pux->Release();
  4081. }
  4082. return fRet;
  4083. }
  4084. COLORREF WINAPI ImageList_SetBkColor(HIMAGELIST himl, COLORREF clrBk)
  4085. {
  4086. COLORREF fRet = clrBk;
  4087. IImageList* pux;
  4088. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageList, &pux))))
  4089. {
  4090. pux->SetBkColor(clrBk, &fRet);
  4091. pux->Release();
  4092. }
  4093. return fRet;
  4094. }
  4095. COLORREF WINAPI ImageList_GetBkColor(HIMAGELIST himl)
  4096. {
  4097. COLORREF fRet = RGB(0,0,0);
  4098. IImageList* pux;
  4099. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageList, &pux))))
  4100. {
  4101. pux->GetBkColor(&fRet);
  4102. pux->Release();
  4103. }
  4104. return fRet;
  4105. }
  4106. BOOL WINAPI ImageList_SetOverlayImage(HIMAGELIST himl, int iImage, int iOverlay)
  4107. {
  4108. BOOL fRet = FALSE;
  4109. IImageList* pux;
  4110. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageList, &pux))))
  4111. {
  4112. fRet = (S_OK == pux->SetOverlayImage(iImage, iOverlay));
  4113. pux->Release();
  4114. }
  4115. return fRet;
  4116. }
  4117. BOOL WINAPI ImageList_Replace(HIMAGELIST himl, int i, HBITMAP hbmImage, HBITMAP hbmMask)
  4118. {
  4119. BOOL fRet = FALSE;
  4120. IImageList* pux;
  4121. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageList, &pux))))
  4122. {
  4123. fRet = (S_OK == pux->Replace(i, hbmImage, hbmMask));
  4124. pux->Release();
  4125. }
  4126. return fRet;
  4127. }
  4128. int WINAPI ImageList_AddMasked(HIMAGELIST himl, HBITMAP hbmImage, COLORREF crMask)
  4129. {
  4130. int fRet = -1;
  4131. IImageList* pux;
  4132. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageList, &pux))))
  4133. {
  4134. pux->AddMasked(hbmImage, crMask, &fRet);
  4135. pux->Release();
  4136. }
  4137. return fRet;
  4138. }
  4139. BOOL WINAPI ImageList_DrawEx(HIMAGELIST himl, int i, HDC hdcDst, int x, int y, int dx, int dy, COLORREF rgbBk, COLORREF rgbFg, UINT fStyle)
  4140. {
  4141. BOOL fRet = FALSE;
  4142. IImageList* pux;
  4143. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageList, &pux))))
  4144. {
  4145. IMAGELISTDRAWPARAMS imldp = {0};
  4146. imldp.cbSize = sizeof(imldp);
  4147. imldp.himl = himl;
  4148. imldp.i = i;
  4149. imldp.hdcDst = hdcDst;
  4150. imldp.x = x;
  4151. imldp.y = y;
  4152. imldp.cx = dx;
  4153. imldp.cy = dy;
  4154. imldp.rgbBk = rgbBk;
  4155. imldp.rgbFg = rgbFg;
  4156. imldp.fStyle = fStyle;
  4157. fRet = (S_OK == pux->Draw(&imldp));
  4158. pux->Release();
  4159. }
  4160. return fRet;
  4161. }
  4162. BOOL WINAPI ImageList_Draw(HIMAGELIST himl, int i, HDC hdcDst, int x, int y, UINT fStyle)
  4163. {
  4164. BOOL fRet = FALSE;
  4165. IImageList* pux;
  4166. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageList, &pux))))
  4167. {
  4168. IMAGELISTDRAWPARAMS imldp = {0};
  4169. imldp.cbSize = sizeof(imldp);
  4170. imldp.himl = himl;
  4171. imldp.i = i;
  4172. imldp.hdcDst = hdcDst;
  4173. imldp.x = x;
  4174. imldp.y = y;
  4175. imldp.rgbBk = CLR_DEFAULT;
  4176. imldp.rgbFg = CLR_DEFAULT;
  4177. imldp.fStyle = fStyle;
  4178. fRet = (S_OK == pux->Draw(&imldp));
  4179. pux->Release();
  4180. }
  4181. return fRet;
  4182. }
  4183. // Note: no distinction between failure case (bad himl) and no flags set
  4184. DWORD WINAPI ImageList_GetItemFlags(HIMAGELIST himl, int i)
  4185. {
  4186. DWORD dwFlags = 0;
  4187. if (himl)
  4188. {
  4189. IImageList* pux;
  4190. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageList, &pux))))
  4191. {
  4192. pux->GetItemFlags(i, &dwFlags);
  4193. pux->Release();
  4194. }
  4195. }
  4196. return dwFlags;
  4197. }
  4198. BOOL WINAPI ImageList_DrawIndirect(IMAGELISTDRAWPARAMS* pimldp)
  4199. {
  4200. BOOL fRet = FALSE;
  4201. IImageList* pux;
  4202. if (!pimldp)
  4203. return fRet;
  4204. if (SUCCEEDED(HIMAGELIST_QueryInterface(pimldp->himl, IID_PPV_ARG(IImageList, &pux))))
  4205. {
  4206. fRet = (S_OK == pux->Draw(pimldp));
  4207. pux->Release();
  4208. }
  4209. return fRet;
  4210. }
  4211. BOOL WINAPI ImageList_Remove(HIMAGELIST himl, int i)
  4212. {
  4213. BOOL fRet = FALSE;
  4214. IImageList* pux;
  4215. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageList, &pux))))
  4216. {
  4217. fRet = (S_OK == pux->Remove(i));
  4218. pux->Release();
  4219. }
  4220. return fRet;
  4221. }
  4222. HICON WINAPI ImageList_GetIcon(HIMAGELIST himl, int i, UINT flags)
  4223. {
  4224. HICON fRet = NULL;
  4225. IImageList* pux;
  4226. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageList, &pux))))
  4227. {
  4228. pux->GetIcon(i, flags, &fRet);
  4229. pux->Release();
  4230. }
  4231. return fRet;
  4232. }
  4233. BOOL WINAPI ImageList_Copy(HIMAGELIST himlDst, int iDst, HIMAGELIST himlSrc, int iSrc, UINT uFlags)
  4234. {
  4235. BOOL fRet = FALSE;
  4236. if (himlDst == himlSrc)
  4237. {
  4238. IImageList* pux;
  4239. if (SUCCEEDED(HIMAGELIST_QueryInterface(himlDst, IID_PPV_ARG(IImageList, &pux))))
  4240. {
  4241. fRet = (S_OK == pux->Copy(iDst,(IUnknown*)pux, iSrc, uFlags));
  4242. pux->Release();
  4243. }
  4244. }
  4245. return fRet;
  4246. }
  4247. BOOL WINAPI ImageList_GetIconSize(HIMAGELIST himl, int *cx, int *cy)
  4248. {
  4249. BOOL fRet = FALSE;
  4250. IImageList* pux;
  4251. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageList, &pux))))
  4252. {
  4253. fRet = (S_OK == pux->GetIconSize(cx, cy));
  4254. pux->Release();
  4255. }
  4256. return fRet;
  4257. }
  4258. BOOL WINAPI ImageList_SetIconSize(HIMAGELIST himl, int cx, int cy)
  4259. {
  4260. BOOL fRet = FALSE;
  4261. IImageList* pux;
  4262. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageList, &pux))))
  4263. {
  4264. fRet = (S_OK == pux->SetIconSize(cx, cy));
  4265. pux->Release();
  4266. }
  4267. return fRet;
  4268. }
  4269. BOOL WINAPI ImageList_GetImageInfo(HIMAGELIST himl, int i, IMAGEINFO* pImageInfo)
  4270. {
  4271. BOOL fRet = FALSE;
  4272. IImageList* pux;
  4273. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageList, &pux))))
  4274. {
  4275. fRet = (S_OK == pux->GetImageInfo(i, pImageInfo));
  4276. pux->Release();
  4277. }
  4278. return fRet;
  4279. }
  4280. HIMAGELIST WINAPI ImageList_Merge(HIMAGELIST himl1, int i1, HIMAGELIST himl2, int i2, int dx, int dy)
  4281. {
  4282. IImageList* fRet = NULL;
  4283. IImageList* pux1;
  4284. IImageList* pux2;
  4285. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl1, IID_PPV_ARG(IImageList, &pux1))))
  4286. {
  4287. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl2, IID_PPV_ARG(IImageList, &pux2))))
  4288. {
  4289. pux1->Merge(i1, (IUnknown*)pux2, i2, dx, dy, IID_PPV_ARG(IImageList, &fRet));
  4290. pux2->Release();
  4291. }
  4292. pux1->Release();
  4293. }
  4294. return reinterpret_cast<HIMAGELIST>(fRet);
  4295. }
  4296. BOOL WINAPI ImageList_SetFlags(HIMAGELIST himl, UINT flags)
  4297. {
  4298. BOOL fRet = FALSE;
  4299. IImageListPriv* pux;
  4300. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageListPriv, &pux))))
  4301. {
  4302. fRet = (S_OK == pux->SetFlags(flags));
  4303. pux->Release();
  4304. }
  4305. return fRet;
  4306. }
  4307. BOOL WINAPI ImageList_SetFilter(HIMAGELIST himl, PFNIMLFILTER pfnFilter, LPARAM lParamFilter)
  4308. {
  4309. return FALSE;
  4310. }
  4311. int ImageList_SetColorTable(HIMAGELIST himl, int start, int len, RGBQUAD *prgb)
  4312. {
  4313. int fRet = -1;
  4314. IImageListPriv* pux;
  4315. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageListPriv, &pux))))
  4316. {
  4317. pux->SetColorTable(start, len, prgb, &fRet);
  4318. pux->Release();
  4319. }
  4320. return fRet;
  4321. }
  4322. UINT WINAPI ImageList_GetFlags(HIMAGELIST himl)
  4323. {
  4324. UINT fRet = 0;
  4325. IImageListPriv* pux;
  4326. if (SUCCEEDED(HIMAGELIST_QueryInterface(himl, IID_PPV_ARG(IImageListPriv, &pux))))
  4327. {
  4328. pux->GetFlags(&fRet);
  4329. pux->Release();
  4330. }
  4331. return fRet;
  4332. }