////////////////////////////////////////////////////////////////////////// // // CBitmapImgCtx // // Implement IImgCtx for drawing out of a bitmap // // WARNING: Incomplete implementation -- just barely enough to keep // listview happy. Should not be exposed to anyone other than listview. // ////////////////////////////////////////////////////////////////////////// #include "ctlspriv.h" #include class CBitmapImgCtx : public IImgCtx { public: // *** IUnknown methods *** STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppv); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); // *** IImgCtx methods *** STDMETHODIMP Load(LPCWSTR pszUrl, DWORD dwFlags); STDMETHODIMP SelectChanges(ULONG ulChgOn, ULONG ulChgOff, BOOL fSignal); STDMETHODIMP SetCallback(PFNIMGCTXCALLBACK pfn, void * pvPrivateData); STDMETHODIMP Disconnect(); STDMETHODIMP GetUpdateRects(LPRECT prc, LPRECT prcImg, LPLONG pcrc); STDMETHODIMP GetStateInfo(PULONG pulState, LPSIZE psize, BOOL fClearChanges); STDMETHODIMP GetPalette(HPALETTE *phpal); STDMETHODIMP Draw(HDC hdc, LPRECT prcBounds); STDMETHODIMP Tile(HDC hdc, LPPOINT pptBackOrg, LPRECT prcClip, LPSIZE psize); STDMETHODIMP StretchBlt(HDC hdc, int dstX, int dstY, int dstXE, int dstYE, int srcX, int srcY, int srcXE, int srcYE, DWORD dwROP); public: CBitmapImgCtx() : _cRef(1) { } BOOL Initialize(HBITMAP hbm); protected: ~CBitmapImgCtx() { if (_hbr) DeleteObject(_hbr); } // Keep _cRef as first member so we can coalesce // with ILVRange's IUnknown implementation int _cRef; HBRUSH _hbr; // Bitmap pattern brush SIZE _sizBmp; // Size of original bitmap PFNIMGCTXCALLBACK _pfnCallback; LPVOID _pvRefCallback; }; STDAPI_(IImgCtx *) CBitmapImgCtx_Create(HBITMAP hbm) { CBitmapImgCtx *pbic = new CBitmapImgCtx(); if (pbic && !pbic->Initialize(hbm)) { pbic->Release(); pbic = NULL; } return pbic; } // CBitmapImgCtx::Initialize BOOL CBitmapImgCtx::Initialize(HBITMAP hbm) { BOOL fSuccess = FALSE; _hbr = CreatePatternBrush(hbm); if (_hbr) { BITMAP bm; if (GetObject(hbm, sizeof(bm), &bm)) { _sizBmp.cx = bm.bmWidth; _sizBmp.cy = bm.bmHeight; fSuccess = TRUE; } } return fSuccess; } // IUnknown::QueryInterface HRESULT CBitmapImgCtx::QueryInterface(REFIID iid, void **ppv) { if (IsEqualIID(iid, IID_IImgCtx) || IsEqualIID(iid, IID_IUnknown)) { *ppv = SAFECAST(this, IImgCtx *); } else { *ppv = NULL; return E_NOINTERFACE; } _cRef++; return NOERROR; } // IUnknown::AddRef ULONG CBitmapImgCtx::AddRef() { return ++_cRef; } // IUnknown::Release ULONG CBitmapImgCtx::Release() { if (--_cRef) return _cRef; delete this; return 0; } // IImgCtx::Load HRESULT CBitmapImgCtx::Load(LPCWSTR pszUrl, DWORD dwFlags) { ASSERT(0); // Listview should never call this return E_NOTIMPL; } // IImgCtx::SelectChanges HRESULT CBitmapImgCtx::SelectChanges(ULONG ulChgOn, ULONG ulChgOff, BOOL fSignal) { // Listview always calls with exactly these parameters ASSERT(ulChgOn == IMGCHG_COMPLETE); ASSERT(ulChgOff == 0); ASSERT(fSignal == TRUE); // Listview always calls after setting the callback ASSERT(_pfnCallback); _pfnCallback(this, _pvRefCallback); return S_OK; } // IImgCtx::SetCallback HRESULT CBitmapImgCtx::SetCallback(PFNIMGCTXCALLBACK pfn, void * pvPrivateData) { _pfnCallback = pfn; _pvRefCallback = pvPrivateData; return S_OK; } // IImgCtx::Disconnect HRESULT CBitmapImgCtx::Disconnect() { ASSERT(0); // Listview should never call this return E_NOTIMPL; } // IImgCtx::GetUpdateRects HRESULT CBitmapImgCtx::GetUpdateRects(LPRECT prc, LPRECT prcImg, LPLONG pcrc) { ASSERT(0); // Listview should never call this return E_NOTIMPL; } // IImgCtx::GetStateInfo HRESULT CBitmapImgCtx::GetStateInfo(PULONG pulState, LPSIZE psize, BOOL fClearChanges) { *pulState = IMGCHG_COMPLETE; *psize = _sizBmp; return S_OK; } // IImgCtx::GetPalette HRESULT CBitmapImgCtx::GetPalette(HPALETTE *phpal) { *phpal = NULL; return S_OK; } // IImgCtx::Draw // // Drawing is a special case of tiling where only one tile's worth // gets drawn. Listview (our only caller) is careful never to ask // for more than one tile's worth, so we can just forward straight // to IImgCtx::Tile(). HRESULT CBitmapImgCtx::Draw(HDC hdc, LPRECT prcBounds) { POINT pt = { prcBounds->left, prcBounds->top }; ASSERT(prcBounds->right - prcBounds->left <= _sizBmp.cx); ASSERT(prcBounds->bottom - prcBounds->top <= _sizBmp.cy); return Tile(hdc, &pt, prcBounds, NULL); } // IImgCtx::Tile HRESULT CBitmapImgCtx::Tile(HDC hdc, LPPOINT pptBackOrg, LPRECT prcClip, LPSIZE psize) { ASSERT(psize == NULL); // Listview always passes NULL POINT pt; if (SetBrushOrgEx(hdc, pptBackOrg->x, pptBackOrg->y, &pt)) { FillRect(hdc, prcClip, _hbr); SetBrushOrgEx(hdc, pt.x, pt.y, NULL); } // Nobody checks the return value return S_OK; } // IImgCtx::StretchBlt HRESULT CBitmapImgCtx::StretchBlt(HDC hdc, int dstX, int dstY, int dstXE, int dstYE, int srcX, int srcY, int srcXE, int srcYE, DWORD dwROP) { ASSERT(0); // Listview should never call this return E_NOTIMPL; }