Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5070 lines
130 KiB

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