2015-03-13 76 views
7

xtow對於,我要畫一個頂層窗口與標準非客戶區和填充有具有alpha通道的位圖在客戶區。繪製窗口與標準幀和透明內容

我現在發現我已經實現了這個適用於Windows 7,但不會在Windows 8.1正確渲染,留下的窗口內容的圖像背後,當它被移動或最大化的方式。

爲了研究,我做了一個簡單的測試程序alpha-test,其

  • 用途DwmEnableBlurBehindWindow()來設置一個非相交模糊區域,因此,在窗口中的α值被兌現,沒有模糊。
  • 使用BitBlt()將帶有alpha的位圖複製到其中。
// 
// g++ alpha-test.cc -o alpha-test -mwindows -lgdiplus -ldwmapi 
// 

#define _WIN32_WINNT 0x0600 

#include <assert.h> 
#include <stdio.h> 
#include <windows.h> 
#include <gdiplus.h> 
#include <dwmapi.h> 

int width = 360; 
int height = 360; 
HBITMAP hBitmap; 

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
    switch (message) 
    { 
    case WM_PAINT: 
     { 
     PAINTSTRUCT ps; 
     HDC hdcUpdate = BeginPaint(hWnd, &ps); 

     RECT rc; 
     GetClientRect(hWnd, &rc); 
     HBRUSH hbrush = CreateSolidBrush(RGB(0,0,0)); 
     FillRect(hdcUpdate, &rc, hbrush); 
     DeleteObject(hbrush); 

     HDC hdcMem = CreateCompatibleDC(hdcUpdate); 
     HBITMAP hbmpold = (HBITMAP)SelectObject(hdcMem, hBitmap); 

     if (!BitBlt(hdcUpdate, 0, 0, ps.rcPaint.right, ps.rcPaint.bottom, hdcMem, 0, 0, SRCCOPY)) 
      { 
      printf("BitBlt failed: 0x%08x\n", (int)GetLastError()); 
      } 

     SelectObject(hdcMem, hbmpold); 
     DeleteDC(hdcMem); 

     EndPaint(hWnd, &ps); 
     } 
     return 0; 

    case WM_DESTROY: 
     PostQuitMessage(0); 
     return 0; 

    default: 
     return DefWindowProc(hWnd, message, wParam, lParam); 
    } 
} 

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) 
{ 
    ULONG_PTR gdiplusToken; 
    Gdiplus::GdiplusStartupInput gdiplusStartupInput; 
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); 

    LPCTSTR szWindowClass = "TransparentClass"; 

    // Register class 
    WNDCLASSEX wcex = {0}; 
    wcex.cbSize = sizeof(WNDCLASSEX); 
    wcex.style   = CS_HREDRAW | CS_VREDRAW; // | CS_OWNDC; 
    wcex.lpfnWndProc = WndProc; 
    wcex.cbClsExtra  = 0; 
    wcex.cbWndExtra  = 0; 
    wcex.hInstance  = hInstance; 
    wcex.hIcon   = NULL; 
    wcex.hCursor  = LoadCursor(NULL, IDC_ARROW); 
    wcex.lpszClassName = szWindowClass; 
    wcex.hIconSm  = NULL; 
    wcex.hbrBackground = (HBRUSH)CreateSolidBrush(0x00000000); 
    RegisterClassEx(&wcex); 

    // Create window 
    HWND hWnd = CreateWindowEx(WS_EX_APPWINDOW, 
          szWindowClass, 
          "Transparent Window", 
          WS_OVERLAPPED | WS_SYSMENU, 
          CW_USEDEFAULT, CW_USEDEFAULT, width, height, 
          NULL, NULL, hInstance, NULL); 

    Gdiplus::Bitmap *m_pImage = Gdiplus::Bitmap::FromFile(L"sample.png", FALSE); 
    Gdiplus::Color bg(0,0,0,0); 
    m_pImage->GetHBITMAP(bg, &hBitmap); 
    assert(hBitmap); 

    DWM_BLURBEHIND blurBehind = { 0 }; 
    blurBehind.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; 
    blurBehind.hRgnBlur = CreateRectRgn(0, 0, -1, -1); 
    blurBehind.fEnable = TRUE; 
    blurBehind.fTransitionOnMaximized = FALSE; 
    DwmEnableBlurBehindWindow(hWnd, &blurBehind); 
    DeleteObject(blurBehind.hRgnBlur); 

    ShowWindow(hWnd, SW_SHOW); 

    // Main message loop 
    MSG msg; 
    while (GetMessage(&msg, NULL, 0, 0)) 
    { 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
    } 

    return (int)msg.wParam; 
} 

這是真的壞了?我如何修復我的代碼?這是Windows錯誤/限制嗎?

是否有另一種方式來實現我的畫帶alpha的位圖到一個窗口邊框的目標是什麼?

更新: 我沒有使用Direct2D和Direct3D來填補與 位圖的客戶區的一些測試,但在相同的方式,他們誤渲染。

回答

1

DWM不會再模糊了(這個功能被認爲太耗電了,並且在Windows 8中被刪除了),所以我猜想它不再適當地合成窗口的背景區域 - 因此你沒有得到「自動」阿爾法效果這是給你在Windows 7

這是一種不同尋常的方式來繪製透明窗口是誠實的。使用UpdateLayeredWindow是「官方」的方式,將有在Windows 8以及Windows 7上工作的好處。

+0

也許我錯過了一些東西,但我認爲使用UpdateLayeredWindow繪製的窗口不會獲得框架,這使得它對我的目的有點不起作用,除非有一些解決方法... – jturney 2015-03-13 20:30:12

+0

@jturney請注意,在Windows 8中,您可以在子窗口上使用'WS_EX_LAYERED'樣式,因此您可能可以這有兩個代碼路徑,使用Windows 7及更早版本的現有方法。你確定你在Windows 7中無法做到嗎? (我從來沒有嘗試過在窗口中啓用任何邊框樣式) – 2015-03-13 20:31:20