In my opinion there is another way to do double buffering. Let me explain.
Let we have the following class (simplified):
Code:
// interface
class CFlickerView : public CView
{
protected:
CFlickerView();
public:
virtual void OnDraw(CDC* pDC);
public:
virtual ~CFlickerView();
protected:
//{{AFX_MSG(CFlickerView)
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
// implementation
void CFlickerView::OnDraw(CDC* pDC)
{
CFlickerDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDC->TextOut(0,0,"Hello world!");
pDC->SelectStockObject(GRAY_BRUSH);
pDC->Ellipse(CRect(0,20,100,120));
}
BOOL CFlickerView::OnEraseBkgnd(CDC* pDC)
{
return TRUE; // for now use the default handling (e.g. fill with solid color)
}
Now, what happen? Windows sends WM_ERASEBKGND and then WM_PAINT (again this is simplified; I know that most of you have solid knowledge about the subject and I’m not trying to teach anybody here but get helped).
The OnEraseBackgroud event is triggered (if there is message map entry for it) and it should erase (e.g. fillrect) the invalidated region. Then OnDraw event is triggered and we painting here on the already erased surface (region). As a result the view flickers like hell... (I know that every one knows that, but let me finish).
So, if we do it like this:
Code:
BOOL CFlickerFreeView::OnEraseBkgnd(CDC* pDC)
{
return TRUE; // do not erase bkgnd and tell framework we handle it
}
void CFlickerFreeView::OnDraw(CDC* pDC)
{
CBitmap TempBitmap;
CBitmap* OldBitmap;
CDC NewDC;
CRect rect;
pOriginalDC=pDC;
OldBitmap=null;
pDC->GetClipBox(&rect);
CDC.CreateCompatibleDC(pDC);
TempBitmap.CreateCompatibleBitmap(pDC, rect.Width(),rect.Height());
OldBitmap = TempDC.SelectObject(&TempBitmap);
TempDC.FillSolidRect(rect, pDC->GetBkColor());
// the painting
TempDC.TextOut(0,0,"Hello world!");
TempDC.SelectStockObject(GRAY_BRUSH);
TempDC.Ellipse(CRect(0,20,100,120));
pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), this, rect.left, rect.top, SRCCOPY);
TempDC.SelectObject(OldBitmap);
}
Fill background (painting on TempDC,TempBitmap) draw the rest, copy bitmap to orgDC.
My idea is to patch message map, vtable or whatever needs to , save the originals and put there another proc (which will reside in dll, assuming dll is loaded by the app) like this:
Code:
pseudo code:
DllInit()
{
//save originals and patch message map or vtable or ??? to point
to WrapperProcOnDraw
}
WrapperProcOnDraw(CDC *pDC)
{
TempDC=CreateTempDCAndBmp; // compatible with the original
FillBackground;
OriginalOnDraw(&TempDC); // call original painting routine
RenderTempDC(pDC); //draw all at once
}
The real question is how to do so? How can i find/patch vtable or message map from within dll? I've already found message map entries for OnEraseBackground and for OnDraw, patched it directly into the exe and it works, but I don't wanna modify the exe. I want to modify running image (.rsrc segment) from within the dll, but don't know how to.
Any ideas are appreciated.