InvalidateRect odd behavior on WinCE/WinMo

时间:2015-05-24 21:27:28

标签: c++ windows mfc windows-ce gdi

I came across some unexplainable and mind blowing behavior while improving drawing routines in a long forgotten application.

In short. Application is cross platform (strong word) program working on Windows NT (and above) and Windows CE (and Mobile).

Now before I show some code (I don't think it's necessary), I will try to explain what the problem is. Application displays many objects on a dialog. To avoid redrawing all of the things I thought to myself, why not to use old solution for that. So I came up with something like this:

void CProblemDialog::OnPaint() 
{
    CRect rect;
    if (!GetUpdateRect(&rect))
        return;

    CPaintDC dc(this);
    CMemDC memDC(&dc); 

    CRgn rgn;
    rgn.CreateRectRgn(rect.left, rect.top, rect.right, rect.bottom);
    _drawer._theClip = &rgn;
    _drawer.PaintOnDC(&memDC);
}

void CDrawer::PaintOnDC(CDC *pDC) 
{
    for (int i = 0; i < _arrElems.GetSize(); i++) {
        CElement *e = (CElement*)_arrCtl.GetAt(i);
        if (e->IsVisible() && _theClip->RectInRegion(e->_rect))
            e->PaintOnDC(pDC);
    }
}

Now this code works well drawing gets done as it supposed to, but there is a little but. Drawer contains list of elements with it coordinates and draws those that somehow intersects with the region. Application receives many external events that tell it to redraw certain parts in the drawer, so each element has a Invalidate method that actually does:

InvalidateRect(this->_rect);

Messages are coming from a network and are queued. When something enters the queue windows message is send to window to process the queue (usually after one element entered the queue), but while main dialog code starts processing the queue it must leave it empty, so when something new arrives it is processed in the same windows message handler (no worries there is a killswitch to avoid flooding). So it might happen (and usually does), that two or more elements need to invalidate "at once".

So here we came to a problem. When in one loop application calls multiple times InvalidateRect, then on mobile platforms it will redraw only first region, rest is untouched. This doesn't happen on "large" windows.

There is one more catch to this. When using a debugger and I break at OnPaint then all is drawn correctly.

Other thing that is odd, that when I'm using BeginPaint/EndPaint method nothing gets drawn on "large" windows, but the above bug is still there for mobile.

Sorry for the long text, but I want you tho know what is going on in the app.

0 个答案:

没有答案