private void PaintNonClientArea(IntPtr hWnd, IntPtr hRgn) { var windowRect = new NativeMethods.RECT(); if (NativeMethods.GetWindowRect(hWnd, ref windowRect) == 0) { return; } var bounds = new Rectangle( 0, 0, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top ); if (bounds.Width == 0 || bounds.Height == 0) { return; } // The update region is clipped to the window frame. When wParam // is 1, the entire window frame needs to be updated. Region clipRegion = null; if (hRgn != (IntPtr)1) { clipRegion = Region.FromHrgn(hRgn); } // MSDN states that only WINDOW and INTERSECTRGN are needed, // but other sources confirm that CACHE is required on Win9x // and you need CLIPSIBLINGS to prevent painting on overlapping windows. var hDC = NativeMethods.GetDCEx( hWnd, hRgn, NativeMethods.DCX_WINDOW | NativeMethods.DCX_INTERSECTRGN | NativeMethods.DCX_CACHE | NativeMethods.DCX_CLIPSIBLINGS ); if (hDC == IntPtr.Zero) { hDC = NativeMethods.GetWindowDC(hWnd); } if (hDC == IntPtr.Zero) { return; } try { var border = _chrome.AdjustedResizeBorderThickness; var clientArea = new Rectangle( border.Left, border.Top + _chrome.CaptionHeight, _form.Width - border.Horizontal, _form.Height - (border.Vertical + _chrome.CaptionHeight) ); if (!_chrome.DoubleBuffered) { using (Graphics graphics = Graphics.FromHdc(hDC)) { graphics.ExcludeClip(clientArea); // Cliping rect is not cliping rect but actual rectangle. _chrome.OnNonClientAreaPaint(new NonClientPaintEventArgs( graphics, bounds, clipRegion, IsMaximized, IsActive )); } // NOTE: The Graphics object would realease the HDC on Dispose. // So there is no need to call NativeMethods.ReleaseDC(msg.HWnd, hDC); // http://groups.google.pl/groups?hl=pl&lr=&c2coff=1&client=firefox-a&rls=org.mozilla:en-US:official_s&threadm=%23DDSaH7BFHA.3644%40TK2MSFTNGP15.phx.gbl&rnum=15&prev=/groups%3Fq%3DWM_NCPaint%2B%2BGetDCEx%26start%3D10%26hl%3Dpl%26lr%3D%26c2coff%3D1%26client%3Dfirefox-a%26rls%3Dorg.mozilla:en-US:official_s%26selm%3D%2523DDSaH7BFHA.3644%2540TK2MSFTNGP15.phx.gbl%26rnum%3D15 // http://groups.google.pl/groups?hl=pl&lr=&c2coff=1&client=firefox-a&rls=org.mozilla:en-US:official_s&threadm=cmo00r%24j9v%241%40mamut1.aster.pl&rnum=1&prev=/groups%3Fq%3DDCX_PARENTCLIP%26hl%3Dpl%26lr%3D%26c2coff%3D1%26client%3Dfirefox-a%26rls%3Dorg.mozilla:en-US:official_s%26selm%3Dcmo00r%2524j9v%25241%2540mamut1.aster.pl%26rnum%3D1 } else { // http://www.codeproject.com/csharp/flicker_free.asp // http://www.pinvoke.net/default.aspx/gdi32/BitBlt.html var compatiblehDc = NativeMethods.CreateCompatibleDC(hDC); var compatibleBitmap = NativeMethods.CreateCompatibleBitmap(hDC, bounds.Width, bounds.Height); try { NativeMethods.SelectObject(compatiblehDc, compatibleBitmap); // copy current screen to bitmap // TODO: this is quite slow (80% of this method). Why? NativeMethods.BitBlt(compatiblehDc, 0, 0, bounds.Width, bounds.Height, hDC, 0, 0, NativeMethods.SRCCOPY); using (Graphics g = Graphics.FromHdc(compatiblehDc)) { g.ExcludeClip(clientArea); //cliping rect is not cliping rect but actual rectangle _chrome.OnNonClientAreaPaint(new NonClientPaintEventArgs( g, bounds, clipRegion, IsMaximized, IsActive )); } // copy current from bitmap to screen NativeMethods.BitBlt(hDC, 0, 0, bounds.Width, bounds.Height, compatiblehDc, 0, 0, NativeMethods.SRCCOPY); } finally { NativeMethods.DeleteObject(compatibleBitmap); NativeMethods.DeleteDC(compatiblehDc); } } } finally { NativeMethods.ReleaseDC(Handle, hDC); } }