问题描述
我试图根据用户设置在具有Aero / Glass和自定义渲染框架(通过处理 code>的 WM_NCPAINT 处理,本机框架现在永久停留在 Vista Basic样式中-它不再是半透明的,并且字幕按钮看起来与
DwmComposition is enabled. My app comes up with the glass frame, but as soon as I toggle the setting to trigger the custom WM_NCPAINT codepath then toggle back to use DefWindowProc's WM_NCPAINT 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.
我几乎尝试过各种方法,例如从发送 SWP_FRAMECHANGED 到更改窗口样式,然后再将其更改,隐藏等,但无济于事。似乎只要为玻璃窗处理 WM_NCPAINT 而不是推迟到 DefWindowProc ,我的窗口就会永远破碎 。
I've tried just about every way of poking the window from sending SWP_FRAMECHANGED 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 WM_NCPAINT for a glass window rather than deferring to DefWindowProc my window is forever "broken".
我在MSDN上发现了一个C#/ WPF示例(代码点msdn点microsoft点com斜杠chrome),它似乎表明一个人只需要停止处理WM_NCPAINT和玻璃会返回,但在我自己的应用中似乎不起作用。
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.
有没有办法彻底重置此状态?我的代码使用C ++,并且位于此处:
Is there a way to reset this state cleanly? My code is in C++ and lives here:
#include <windows.h> #include <dwmapi.h> 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(&composition_enabled) == S_OK && composition_enabled && 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, &ps); GetClientRect(hwnd, &wr); br = GetSysColorBrush(IsGlass() ? COLOR_APPWORKSPACE : COLOR_WINDOW); FillRect(hdc, &wr, br); EndPaint(hwnd, &ps); break; case WM_NCPAINT: if (IsGlass()) return DefWindowProc(hwnd, message, w_param, l_param); GetWindowRect(hwnd, &wr); if (!w_param|| w_param == 1) { dirty = wr; dirty.left = dirty.top = 0; } else { GetRgnBox(reinterpret_cast<HRGN>(w_param), &dirty_box); if (!IntersectRect(&dirty, &dirty_box, &wr)) return 0; OffsetRect(&dirty, -wr.left, -wr.top); } hdc = GetWindowDC(hwnd); br = CreateSolidBrush(RGB(255,0,0)); FillRect(hdc, &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 ? &reinterpret_cast<NCCALCSIZE_PARAMS*>(l_param)->rgrc[0] : reinterpret_cast<RECT*>(l_param); nccr->bottom -= IsGlass() ? kGlassBorderSize : kNonGlassBorderSize; nccr->right -= IsGlass() ? kGlassBorderSize : kNonGlassBorderSize; nccr->left += IsGlass() ? kGlassBorderSize : kNonGlassBorderSize; nccr->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, &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(&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(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return static_cast<int>(msg.wParam); }
推荐答案
在Aero / Glass之间切换时以及您自定义的渲染框架,您可以使用以下内容显式控制非客户区域渲染策略:
When toggling between Aero/Glass and your custom rendered frame it you can use the following to explicitly control the non-client area rendering policy:
DWMNCRENDERINGPOLICY policy = DWMNCRP_ENABLED; // DWMNCRP_DISABLED to toggle back DwmSetWindowAttribute(hwnd, DWMWA_NCRENDERING_POLICY, (void*)&policy, sizeof(DWMNCRENDERINGPOLICY));
这篇关于处理WM_NCPAINT的“中断”。在Vista / Aero上进行DWM玻璃渲染的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!