对于xtow ,我想绘制一个标准的非客户区域的顶层窗口,客户区域填充了一个有alpha通道的位图。
我现在发现,我已经在Windows 7上实现了这个工作,但是在Windows 8.1上不能正确显示,当窗口内容被移动或最大化时,留下窗口内容的图像。
为了调查,我做了一个简单的testing程序阿尔法testing ,其中
// // 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的testing来填充位图的客户区,但是它们以相同的方式渲染错误。
DWM不再模糊(这个功能被认为太耗电了,并在Windows 8中被删除),所以我猜测它不能正确地合成窗口的背景区域 – 因此你不是获得它在Windows 7中给你的“自动”alpha效果。
这是一种不寻常的方式来绘制透明的窗户是诚实的。 使用UpdateLayeredWindow
是“官方”的方式,将有Windows 8和Windows 7的好处。