处理WM_NCPAINT的“中断”。在Vista / Aero上进行DWM玻璃渲染 [英] Handling WM_NCPAINT "breaks" DWM glass rendering on Vista/Aero

查看:116
本文介绍了处理WM_NCPAINT的“中断”。在Vista / Aero上进行DWM玻璃渲染的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图根据用户设置在具有Aero / Glass和自定义渲染框架(通过处理 WM_NCPAINT )之间切换一个窗口。 (Windows Vista)。

I am trying to make a window that alternates between having an Aero/Glass and a custom rendered frame (by handling WM_NCPAINT) based on a user setting. (Windows Vista).

DwmComposition 已启用。我的应用程序带有玻璃框,但是一旦我切换设置以触发自定义 WM_NCPAINT 代码路径,然后切换回使用 DefWindowProc 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:

http://bengoodger.dreamhosters.com/software/chrome/dwm/

#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玻璃渲染的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆