The problem: When you resize a window horizontally and vertically by even a tiny bit (1 pixel) WM_PAINT combines the obvious two very small update regions into one update rectangle that is the smalles enclosing rectangle around those two regions--which is in this case the whole window!
The solution: We need to paint based on update regions instead of the single update rect!
Why its less than totally easy: Windows gives us easy access to the update rect but not the individual rectangular components of the update region. You have to do some gyrations to get the these.
First we have to create a region to receive our update region. I just
make an empty region to do this. Use CreateRectRgn().
Next we ask windows for the update region. Use GetUpdateRgn().
We wont have a valid region to paint if we get an error or a null region
so check for those return codes from GetUpdateRgn().
Now we have to get the component shapes of that region. MSDN tells me
they could be all sorts of exotic shapes but for now they're just
rectangles. Ok, so assume they're rectangles. Use
GetRegionData().
Now we have rgndata->rdh.nCount rectangles to paint. loop through
them. We can get a rectangle to paint from ((RECT
*)rgndata->buffer)[i].
Now we only want to revalidate the rectangle that we're currently painting
so use ValidateRect() carefully.
Once we're done looping through the region's rectangles, we're done with
the region data. So you can free it.
If we GetUpdateRgn() failed, we still have the region we created for it to
fill in with CreateRectRgn(). Dont forget to use
DeleteObject(hrgn)!
Note that we don't use BeginPaint() or EndPaint(). This is because
BeginPaint() validates the entire update region, so our call to
GetUpdateRgn() will not work because there will be no invalidated region
left to update. Of course we have to validate the rect ourself which is
something you may not be used to doing. There may be other functionality
of BeginPaint() and EndPaint() you need to duplicate.
Here's the code i was looking at:
RGNDATA *rgndata;
HDC paintdc;
int gotregion;
int i,l,w,h;
RECT r;
HRGN hrgn;
HWND hWnd;
//create a region to receive the window update region
hrgn=CreateRectRgn(0,0,0,0);
//try to get the window update region.
gotregion=GetUpdateRgn(hWnd,hrgn,0);
//we may not have got a region. in that case there is nothing to paint
if(gotregion!=NULLREGION&&gotregion!=ERROR)
{
//get the region data from the region so we know what to paint
rgndata=(RGNDATA*)malloc(i=GetRegionData(hrgn,0,0));
GetRegionData(hrgn,i,rgndata);
//since we've gotten its data, we're done with the region
DeleteObject(hrgn);
//grab the paint dc
paintdc=GetDC(hWnd);
//paint each rect in the region
for(l=0;lrdh.nCount;l++)
{
//find out the dimensions of the rect we're to paint
r=((RECT *)rgndata->Buffer)[l];
w=r.right-r.left;
h=r.bottom-r.top;
//go ahead and validate it!
ValidateRect(hWnd,&r);
//do some painting....
}
//release the paintdc
ReleaseDC(hWnd,paintdc);
//we're done updating rects, so get rid of the update rect list
free(rgndata);
}
else //we couldnt getupdateregion, but we still have a rgn to delete
{
DeleteObject(hrgn);
}