2009-07-18 6 views
10

J'essaie de créer une fenêtre qui alterne entre un Aero/Glass et un rendu personnalisé (en traitant WM_NCPAINT) en fonction d'un paramètre utilisateur. (Windows Vista).Gestion de WM_NCPAINT "Ruptures" du rendu du verre DWM sous Vista/Aero

DwmComposition est activé. Mon application arrive avec le cadre en verre, mais dès que je bascule le paramètre pour déclencher le chemin de code WM_NCPAINT personnalisé, puis basculer pour utiliser la manipulation de DefWindowProcWM_NCPAINT, le cadre natif est maintenant perpétuellement coincé dans le style "Vista Basic" - il est ne sont plus translucides et les boutons de légende ont un aspect différent des boutons Aero/Glass normaux.

J'ai essayé à peu près tous les moyens de piquer la fenêtre d'envoyer SWP_FRAMECHANGED à changer le style de la fenêtre, puis le changer, le cacher, etc, mais en vain. Il semble que dès que je gère WM_NCPAINT pour une fenêtre en verre plutôt que de se reporter à DefWindowProc ma fenêtre est pour toujours "brisée".

J'ai trouvé un exemple C#/WPF sur MSDN (code point msdn point microsoft dot com slash chrome) qui semblait indiquer qu'il fallait simplement arrêter de gérer WM_NCPAINT et le verre reviendrait, mais cela ne semble pas fonctionner dans ma propre application.

Y at-il un moyen de réinitialiser cet état proprement? Mon code est en C++ et vit ici:

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); 
} 

Répondre

14

Lorsque basculer entre Aero/verre et votre cadre rendu personnalisé, il vous pouvez utiliser ce qui suit pour contrôler explicitement la zone non-client rendu politique:

DWMNCRENDERINGPOLICY policy = DWMNCRP_ENABLED; // DWMNCRP_DISABLED to toggle back 
DwmSetWindowAttribute(hwnd, 
         DWMWA_NCRENDERING_POLICY, 
         (void*)&policy, 
         sizeof(DWMNCRENDERINGPOLICY)); 
+0

Doux, cela a fonctionné. Je l'avais essayé plus tôt, mais j'avais le sens de la politique inversé. Merci! –

Questions connexes