Note that there are some explanatory texts on larger screens.

plurals
  1. POHandling WM_NCPAINT "breaks" DWM glass rendering on Vista/Aero
    primarykey
    data
    text
    <p>I am trying to make a window that alternates between having an Aero/Glass and a custom rendered frame (by handling <code>WM_NCPAINT</code>) based on a user setting. (Windows Vista).</p> <p><code>DwmComposition</code> is enabled. My app comes up with the glass frame, but as soon as I toggle the setting to trigger the custom <code>WM_NCPAINT</code> codepath then toggle back to use <code>DefWindowProc</code>'s <code>WM_NCPAINT</code> handling, the native frame is now perpetually stuck in the "Vista Basic" style - it's no longer translucent and the caption buttons look different to the normal Aero/Glass ones.</p> <p>I've tried just about every way of poking the window from sending <code>SWP_FRAMECHANGED</code> to changing the window style then changing it back, hiding it, etc, but all to no avail. It seems like as soon as I handle <code>WM_NCPAINT</code> for a glass window rather than deferring to <code>DefWindowProc</code> my window is forever "broken".</p> <p>I found a C#/WPF example on MSDN (code dot msdn dot microsoft dot com slash chrome ) that seemed to indicate that one simply needed to stop handling WM_NCPAINT and the glass would return, but that does not seem to work in my own app.</p> <p>Is there a way to reset this state cleanly? My code is in C++ and lives here:</p> <p><a href="http://bengoodger.dreamhosters.com/software/chrome/dwm/" rel="noreferrer">http://bengoodger.dreamhosters.com/software/chrome/dwm/</a></p> <pre><code>#include &lt;windows.h&gt; #include &lt;dwmapi.h&gt; static const wchar_t* kWindowClass = L"BrokenGlassWindow"; static const wchar_t* kWindowTitle = L"BrokenGlass - Right click client area to toggle frame type."; static const int kGlassBorderSize = 50; static const int kNonGlassBorderSize = 40; static bool g_glass = true; bool IsGlass() { BOOL composition_enabled = FALSE; return DwmIsCompositionEnabled(&amp;composition_enabled) == S_OK &amp;&amp; composition_enabled &amp;&amp; g_glass; } void SetIsGlass(bool is_glass) { g_glass = is_glass; } void ToggleGlass(HWND hwnd) { SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED); RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM w_param, LPARAM l_param) { PAINTSTRUCT ps; HDC hdc; RECT wr; HBRUSH br; RECT* nccr = NULL; RECT dirty; RECT dirty_box; MARGINS dwmm = {0}; WINDOWPOS* wp = NULL; switch (message) { case WM_CREATE: SetCursor(LoadCursor(NULL, IDC_ARROW)); break; case WM_ERASEBKGND: return 1; case WM_PAINT: hdc = BeginPaint(hwnd, &amp;ps); GetClientRect(hwnd, &amp;wr); br = GetSysColorBrush(IsGlass() ? COLOR_APPWORKSPACE : COLOR_WINDOW); FillRect(hdc, &amp;wr, br); EndPaint(hwnd, &amp;ps); break; case WM_NCPAINT: if (IsGlass()) return DefWindowProc(hwnd, message, w_param, l_param); GetWindowRect(hwnd, &amp;wr); if (!w_param|| w_param == 1) { dirty = wr; dirty.left = dirty.top = 0; } else { GetRgnBox(reinterpret_cast&lt;HRGN&gt;(w_param), &amp;dirty_box); if (!IntersectRect(&amp;dirty, &amp;dirty_box, &amp;wr)) return 0; OffsetRect(&amp;dirty, -wr.left, -wr.top); } hdc = GetWindowDC(hwnd); br = CreateSolidBrush(RGB(255,0,0)); FillRect(hdc, &amp;dirty, br); DeleteObject(br); ReleaseDC(hwnd, hdc); break; case WM_NCACTIVATE: // Force paint our non-client area otherwise Windows will paint its own. RedrawWindow(hwnd, NULL, NULL, RDW_UPDATENOW); break; case WM_NCCALCSIZE: nccr = w_param ? &amp;reinterpret_cast&lt;NCCALCSIZE_PARAMS*&gt;(l_param)-&gt;rgrc[0] : reinterpret_cast&lt;RECT*&gt;(l_param); nccr-&gt;bottom -= IsGlass() ? kGlassBorderSize : kNonGlassBorderSize; nccr-&gt;right -= IsGlass() ? kGlassBorderSize : kNonGlassBorderSize; nccr-&gt;left += IsGlass() ? kGlassBorderSize : kNonGlassBorderSize; nccr-&gt;top += IsGlass() ? kGlassBorderSize : kNonGlassBorderSize; return WVR_REDRAW; case WM_RBUTTONDOWN: SetIsGlass(!g_glass); ToggleGlass(hwnd); break; case 0x31E: // WM_DWMCOMPOSITIONCHANGED: ToggleGlass(hwnd); break; case 0xAE: // WM_NCUAHDRAWCAPTION: case 0xAF: // WM_NCUAHDRAWFRAME: return IsGlass() ? DefWindowProc(hwnd, message, w_param, l_param) : 0; case WM_WINDOWPOSCHANGED: dwmm.cxLeftWidth = kGlassBorderSize; dwmm.cxRightWidth = kGlassBorderSize; dwmm.cyTopHeight = kGlassBorderSize; dwmm.cyBottomHeight = kGlassBorderSize; DwmExtendFrameIntoClientArea(hwnd, &amp;dwmm); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, message, w_param, l_param); } return 0; } ATOM RegisterClazz(HINSTANCE instance) { WNDCLASSEX wcex = {0}; wcex.cbSize = sizeof(wcex); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.hInstance = instance; wcex.lpszClassName = kWindowClass; return RegisterClassEx(&amp;wcex); } int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int show_command) { RegisterClazz(instance); HWND hwnd = CreateWindow(kWindowClass, kWindowTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, instance, NULL); ShowWindow(hwnd, show_command); MSG msg; while (GetMessage(&amp;msg, NULL, 0, 0)) { TranslateMessage(&amp;msg); DispatchMessage(&amp;msg); } return static_cast&lt;int&gt;(msg.wParam); } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload