Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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