2009-07-18 8 views
10

사용자 설정에 따라 Aero/Glass와 사용자 정의 렌더링 프레임 (WM_NCPAINT 처리)을 번갈아 가며 창을 만들려고합니다. (Windows Vista).WM_NCPAINT 처리 Vista/Aero에서 DWM 유리 렌더링 "깨뜨림"

DwmComposition이 사용 가능합니다. 내 응용 프로그램은 유리 프레임으로 표시되지만 사용자 정의 WM_NCPAINT 코드 경로를 설정하도록 전환 한 다음 DefWindowProcWM_NCPAINT 처리를 사용하도록 전환하면 이제 원시 프레임이 "Vista 기본"스타일로 영원히 멈추게됩니다. 더 이상 반투명이 아니며 캡션 버튼이 일반적인 Aero/Glass와 다르게 보입니다.

저는 창 스타일을 변경 한 다음 SWP_FRAMECHANGED을 보내고 창을 바꿔 가며 숨기는 등 모든 방법을 시도했지만 모든 것을 사용할 수는 없습니다. DefWindowProc으로 연기하는 대신 유리창에 대해 WM_NCPAINT을 처리하자마자 내 창은 영원히 "깨졌습니다".

WM_NCPAINT의 처리를 중지하고 유리가 반환 될 필요가 있음을 나타내는 것처럼 보인 MSDN (코드 도트 MSDN 도트 마이크로 소프트 도트 슬래시 크롬)에서 C#/WPF 예제를 발견했지만 작동하지 않는 것 같습니다. 내 자신의 응용 프로그램.

이 상태를 깨끗하게 재설정 할 수있는 방법이 있습니까? 내 코드는 C++에 여기에 살고 :

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

답변

14

가 명시 적으로 비 클라이언트 영역 렌더링 정책을 제어하려면 다음을 사용할 수 있습니다 에어로/유리 및 사용자 정의 렌더링 프레임을 사이에 전환 할 때 :

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

달콤합니다. 나는 이것을 일찍 시도했지만, 정책 감각이 뒤 바뀌었다. 감사! –