对于xtow,我想绘制一个顶级窗口,其中包含标准的非客户区域,客户区域填充了一个具有alpha通道的位图.
我现在发现我在Windows 7上实现此方法的方法,但在Windows 8.1上无法正确呈现,在移动或最大化时留下窗口内容的图像.
为了调查,我做了一个简单的测试程序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的bug /限制吗?
是否有另一种方法可以实现我的目标,即将带有alpha的位图绘制到带边框的窗口中?
更新: 我使用Direct2D和Direct3D进行了一些测试,用位图填充客户区,但是它们以相同的方式错误渲染.
DWM 不再进行模糊处理(此功能被认为太耗电,并在 Windows 8 中被删除),因此我猜测它不再正确地合成窗口的背景区域 - 因此您不会获得 Windows 7 中提供的“自动”Alpha 效果。
老实说,这是一种不寻常的绘制透明窗口的方法。使用UpdateLayeredWindow是“官方”方式,并且可以在 Windows 8 和 Windows 7 上工作。
| 归档时间: | 
 | 
| 查看次数: | 563 次 | 
| 最近记录: |