المساعد الشخصي الرقمي

مشاهدة النسخة كاملة : WM_NCCALCSIZE bug with Vista Desktop Composition



C++ Programming
03-31-2009, 07:40 PM
I have posted this a few days ago in connect microsoft but apart from an automatic reply I had no more feedback and I was wondering if anybody here had already found this bug before.

It seems the WM_NCCALCSIZE message is not being correctly processed by Windows Vista when Desktop Composition is enabled. The identified behavior was only detected when Desktop Composition is enabled. If Desktop Composition is disabled, everything works fine. It also works fine on XP.

The idea behind the tests that lead to the bug was to use the WM_NCCALCSIZE message and the NCCALCSIZE_PARAMS structure to implement a window client area preservation scheme, in order to minimize flickering due to unnecessary processing of WM_PAINT messages. The window style was registered without the (CS_HREDRAW | CS_VREDRAW) flags.
The goal was to avoid having to process the WM_PAINT message when the window was being resized due to the dragging of the window left border to the right. The usual procedure, in most applications (e.g. Notepad), would be to keep the client area content aligned left. In my case a bitmap is being displayed on the client area and the intention was to keep it right aligned (not left aligned) when the window left border was being dragged. So, dragging the left border to the right would cover some portion on the left part of the bitmap, originally displayed on the client area. The remaining part of the bitmap (the part on the right) could be completely preserved and processing the WM_PAINT message could be avoided.
The rectangles on the NCCALCSIZE_PARAMS structure were processed so that the system would copy the window image that is within the source rectangle and clips the image to the destination rectangle. In this case both source and destination client area rectangles refer to the same coordinates (the bit map right portion, not covered by the drag of the left border to the right). As the result of processing the WM_NCCALCSIZE message (and NCCALCSIZE_PARAMS structure), WVR_VALIDRECTS was returned, according to the documentation.
If Windows Vista Desktop Composition is enable the content of the NCCALCSIZE_PARAMS structure seems to be ignored and the bitmap on the client area is kept left aligned (dragged to the right as the window left border is dragged to the right). Everything works fine if Desktop Composition is disabled.
An identical bug can be reproduced by resizing the window dragging the top window border in the bottom direction (the bottom part of the bitmap should be preserved and instead it is top alligned and dragged down).


The following steps describe a small sample code intended to demonstrate the behaviour previously described and nothing else.
A new empty win32 project was created.
A global variable was created to accommodate the bitmap handle:
HANDLE g_hBitmap;
The window style is registered in MyRegisterClass as
wcex.style = CS_DBLCLKS /*| CS_HREDRAW | CS_VREDRAW*/;
In InitInstance a bitmap is loaded after CreateWindow:
g_hBitmap=LoadImage(0, // Load an OEM Image
TEXT("bitmap.bmp"),
IMAGE_BITMAP, // Type of image to be loadedd
0, // Uses the actual resource width
0, // Uses the actual resource height
LR_CREATEDIBSECTION|LR_LOADFROMFILE);
In the WndProc callback the following variables and references were defined to support the following code:
HDC hdcMem;
RECT rect;
LONG& width=rect.right; // rect.left=0 (see GetClientRect)
LONG& height=rect.bottom; // rect.top=0 (see GetClientRect)
In the WndProc callback the following code was inserted:
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
GetClientRect(hWnd,&rect);
// Create a DC that matches the device
hdcMem=CreateCompatibleDC(hdc);
// Select the bitmap into the compatible DC
SelectObject(hdcMem, g_hBitmap);
BitBlt(hdc,0,0,width,height,hdcMem,0,0,SRCCOPY);
// Delete the Memory DC
DeleteDC(hdcMem);
EndPaint(hWnd, &ps);
break;
case WM_NCCALCSIZE:
if(wParam==TRUE)
{
RECT r, ro;
NCCALCSIZE_PARAMS& s=*((NCCALCSIZE_PARAMS*)lParam);
// s.rgrc[0]: new window rect
// s.rgrc[1]: old window rect
// s.rgrc[2]: old client area
// new client area:
r.left=s.rgrc[2].left+(s.rgrc[0].left-s.rgrc[1].left);
r.right=s.rgrc[2].right+(s.rgrc[0].right-s.rgrc[1].right);
r.top=s.rgrc[2].top+(s.rgrc[0].top-s.rgrc[1].top);
r.bottom=s.rgrc[2].bottom+(s.rgrc[0].bottom-s.rgrc[1].bottom);
s.rgrc[0]=r; // return new client area
// check to see if something can be used from the old client area
if(IntersectRect(&ro,&r,&s.rgrc[2]))
{
// s.rgrc[1]: destination client rect
// s.rgrc[2]: source client rect
s.rgrc[1]=s.rgrc[2]=ro; // destination and source rectangles
return WVR_VALIDRECTS;
}
return 0;
}
else//wParam==FALSE
return DefWindowProc(hWnd,message,wParam,lParam); // wParam==FALSE
break;